diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7f71847..af34bd4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,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].
+- Added JWT digital signature verification by using the RSA public key of the realm on server. Uses `java-jwt` library by Auth0 [#27340]
## [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).
diff --git a/pom.xml b/pom.xml
index 10f7ed4..9b9a9d4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,8 +7,7 @@
maven-parent
org.gcube.tools
- 1.1.0
-
+ 1.2.0
org.gcube.common
@@ -33,6 +32,12 @@
https://code-repo.d4science.org/gCubeSystem/${project.artifactId}
+
+ 1.8
+ ${java.version}
+ ${java.version}
+
+
@@ -60,6 +65,12 @@
gxJRS
+
+ com.auth0
+ java-jwt
+ 4.4.0
+
+
org.slf4j
slf4j-log4j12
diff --git a/src/main/java/org/gcube/common/keycloak/DefaultKeycloakClient.java b/src/main/java/org/gcube/common/keycloak/DefaultKeycloakClient.java
index e592f89..e065d7a 100644
--- a/src/main/java/org/gcube/common/keycloak/DefaultKeycloakClient.java
+++ b/src/main/java/org/gcube/common/keycloak/DefaultKeycloakClient.java
@@ -38,9 +38,12 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+import org.gcube.common.gxhttp.util.ContentUtils;
import org.gcube.common.gxrest.request.GXHTTPStringRequest;
import org.gcube.common.gxrest.response.inbound.GXInboundResponse;
+import org.gcube.common.gxrest.response.inbound.JsonUtils;
import org.gcube.common.keycloak.model.ModelUtils;
+import org.gcube.common.keycloak.model.PublishedRealmRepresentation;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
import org.slf4j.Logger;
@@ -176,11 +179,80 @@ public class DefaultKeycloakClient implements KeycloakClient {
}
}
+ @Override
+ public PublishedRealmRepresentation getRealmInfo(URL realmURL) throws KeycloakClientException {
+ try {
+ return JsonUtils.fromJson(ContentUtils.toByteArray(realmURL.openStream()),
+ PublishedRealmRepresentation.class);
+ } catch (Exception e) {
+ throw new KeycloakClientException("Getting realm's info", e);
+ }
+ }
+
@Override
public TokenResponse queryOIDCToken(String context, String clientId, String clientSecret)
throws KeycloakClientException {
- return queryOIDCTokenWithContext(context, clientId, clientSecret, null);
+ return queryOIDCToken(context, clientId, clientSecret, null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(String context, String clientId, String clientSecret,
+ Map extraHeaders) throws KeycloakClientException {
+
+ return queryOIDCToken(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret)
+ throws KeycloakClientException {
+
+ return queryOIDCToken(tokenURL, clientId, clientSecret, null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret,
+ Map extraHeaders) throws KeycloakClientException {
+
+ return queryOIDCTokenWithContext(tokenURL, clientId, clientSecret, null, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(String context, String authorization) throws KeycloakClientException {
+ return queryOIDCTokenWithContext(context, authorization, null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(URL tokenURL, String authorization) throws KeycloakClientException {
+ return queryOIDCToken(tokenURL, authorization, (Map) null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(String context, String authorization, Map extraHeaders)
+ throws KeycloakClientException {
+
+ return queryOIDCToken(getTokenEndpointURL(getRealmBaseURL(context)), authorization, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCToken(URL tokenURL, String authorization, Map extraHeaders)
+ throws KeycloakClientException {
+
+ return queryOIDCTokenWithContext(tokenURL, authorization, null, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
+ String password) throws KeycloakClientException {
+
+ return queryOIDCTokenOfUser(context, clientId, clientSecret, username, password, null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
+ String password, Map extraHeaders) throws KeycloakClientException {
+
+ return queryOIDCTokenOfUserWithContext(context, clientId, clientSecret, username, password, null, extraHeaders);
}
@Override
@@ -192,46 +264,70 @@ public class DefaultKeycloakClient implements KeycloakClient {
}
@Override
- public TokenResponse queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
- String password) throws KeycloakClientException {
-
- 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) null);
- }
-
- @Override
- public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
- String username, String password, String audience, Map extraHeaders) throws KeycloakClientException {
-
- return queryOIDCTokenOfUserWithContext(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
- username, password, audience, extraHeaders);
- }
-
- @Override
- public TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret)
+ public TokenResponse queryOIDCTokenWithContext(String context, String authorization, String audience)
throws KeycloakClientException {
-
- return queryOIDCTokenWithContext(tokenURL, clientId, clientSecret, null);
+ return queryOIDCTokenWithContext(getTokenEndpointURL(getRealmBaseURL(context)), authorization, audience);
}
@Override
public TokenResponse queryOIDCTokenWithContext(URL tokenURL, String clientId, String clientSecret,
String audience) throws KeycloakClientException {
+ return queryOIDCTokenWithContext(tokenURL, clientId, clientSecret, audience, null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenWithContext(String context, String clientId, String clientSecret,
+ String audience, Map extraHeaders) throws KeycloakClientException {
+
+ return queryOIDCTokenWithContext(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
+ audience, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenWithContext(URL tokenURL, String clientId, String clientSecret, String audience,
+ Map extraHeaders) throws KeycloakClientException {
+
return queryOIDCTokenWithContext(tokenURL, constructBasicAuthenticationHeader(clientId, clientSecret),
- audience);
+ audience, extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenWithContext(String context, String authorization, String audience,
+ Map extraHeaders) throws KeycloakClientException {
+
+ return queryOIDCTokenWithContext(getTokenEndpointURL(getRealmBaseURL(context)), authorization, audience,
+ extraHeaders);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenWithContext(URL tokenURL, String authorization, String audience)
+ throws KeycloakClientException {
+
+ return queryOIDCTokenWithContext(tokenURL, authorization, audience, (Map) null);
}
protected static String constructBasicAuthenticationHeader(String clientId, String clientSecret) {
return "Basic " + Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes());
}
+ @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) null);
+ }
+
+ @Override
+ public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
+ String username, String password, String audience, Map extraHeaders)
+ throws KeycloakClientException {
+
+ return queryOIDCTokenOfUserWithContext(getTokenEndpointURL(getRealmBaseURL(context)), clientId, clientSecret,
+ username, password, audience, extraHeaders);
+ }
+
@Override
public TokenResponse queryOIDCTokenOfUserWithContext(String context, String authorization, String username,
String password, String audience) throws KeycloakClientException {
@@ -248,27 +344,18 @@ public class DefaultKeycloakClient implements KeycloakClient {
password, audience, extraHeaders);
}
- @Override
- public TokenResponse queryOIDCToken(String context, String authorization) throws KeycloakClientException {
- return queryOIDCTokenWithContext(context, authorization, null);
- }
-
- @Override
- public TokenResponse queryOIDCTokenWithContext(String context, String authorization, String audience)
- throws KeycloakClientException {
- return queryOIDCTokenWithContext(getTokenEndpointURL(getRealmBaseURL(context)), authorization, audience);
- }
-
@Override
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) null);
+ return queryOIDCTokenOfUserWithContext(tokenURL, clientId, clientSecret, username, password, audience,
+ (Map) null);
}
@Override
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret,
- String username, String password, String audience, Map extraHeaders) throws KeycloakClientException {
+ String username, String password, String audience, Map extraHeaders)
+ throws KeycloakClientException {
return queryOIDCTokenOfUserWithContext(tokenURL, constructBasicAuthenticationHeader(clientId, clientSecret),
username, password, audience, extraHeaders);
@@ -278,7 +365,8 @@ public class DefaultKeycloakClient implements KeycloakClient {
public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username,
String password, String audience) throws KeycloakClientException {
- return queryOIDCTokenOfUserWithContext(tokenURL, authorization, username, password, audience, (Map) null);
+ return queryOIDCTokenOfUserWithContext(tokenURL, authorization, username, password, audience,
+ (Map) null);
}
@Override
@@ -289,6 +377,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
params.put(GRANT_TYPE_PARAMETER, Arrays.asList(PASSWORD_GRANT_TYPE));
params.put(USERNAME_PARAMETER, Arrays.asList(username));
params.put(PASSWORD_PARAMETER, Arrays.asList(password));
+ params.put(SCOPE_PARAMETER, Arrays.asList("openid profile " + OFFLINE_ACCESS_SCOPE));
Map headers = new HashMap<>();
logger.debug("Adding authorization header as: {}", authorization);
@@ -307,12 +396,8 @@ public class DefaultKeycloakClient implements KeycloakClient {
}
@Override
- public TokenResponse queryOIDCToken(URL tokenURL, String authorization) throws KeycloakClientException {
- return queryOIDCTokenWithContext(tokenURL, authorization, null);
- }
-
- @Override
- public TokenResponse queryOIDCTokenWithContext(URL tokenURL, String authorization, String audience)
+ public TokenResponse queryOIDCTokenWithContext(URL tokenURL, String authorization, String audience,
+ Map extraHeaders)
throws KeycloakClientException {
logger.debug("Querying OIDC token from Keycloak server with URL: {}", tokenURL);
@@ -415,27 +500,47 @@ public class DefaultKeycloakClient implements KeycloakClient {
protected TokenResponse performRequest(URL tokenURL, Map headers, Map> params)
throws KeycloakClientException {
- if (tokenURL == null) {
+ return performRequest(TokenResponse.class, tokenURL, headers, params);
+ }
+
+ protected T performRequest(Class returnObjectClass, URL url, Map headers,
+ Map> params)
+ throws KeycloakClientException {
+
+ if (url == null) {
throw new KeycloakClientException("Token URL must be not null");
}
// Constructing request object
GXHTTPStringRequest request;
try {
- String queryString = params.entrySet().stream()
- .flatMap(p -> p.getValue().stream().map(v -> p.getKey() + "=" + v))
- .reduce((p1, p2) -> p1 + "&" + p2).orElse("");
+ String queryString = "";
+ if (params != null) {
+ queryString = params.entrySet().stream()
+ .flatMap(p -> p.getValue().stream().map(v -> p.getKey() + "=" + v))
+ .reduce((p1, p2) -> p1 + "&" + p2).orElse("");
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Params map is null");
+ }
+ }
logger.trace("Query string is: {}", queryString);
- request = GXHTTPStringRequest.newRequest(tokenURL.toString())
+ request = GXHTTPStringRequest.newRequest(url.toString())
.header("Content-Type", "application/x-www-form-urlencoded").withBody(queryString);
safeSetAsExternalCallForOldAPI(request);
- logger.trace("Adding provided headers: {}", headers);
- for (String headerName : headers.keySet()) {
- request.header(headerName, headers.get(headerName));
+ if (headers != null) {
+ logger.trace("Adding provided headers: {}", headers);
+ for (String headerName : headers.keySet()) {
+ request.header(headerName, headers.get(headerName));
+ }
+ } else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("HTTP headers map is null");
+ }
}
} catch (Exception e) {
throw new KeycloakClientException("Cannot construct the request object correctly", e);
@@ -450,7 +555,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
}
if (response.isSuccessResponse()) {
try {
- return response.tryConvertStreamedContentFromJson(TokenResponse.class);
+ return response.tryConvertStreamedContentFromJson(returnObjectClass);
} catch (Exception e) {
throw new KeycloakClientException("Cannot construct token response object correctly", e);
}
@@ -538,99 +643,73 @@ public class DefaultKeycloakClient implements KeycloakClient {
logger.debug("Refreshing token from Keycloak server with URL: {}", tokenURL);
- // Constructing request object
- GXHTTPStringRequest request;
try {
- Map params = new HashMap<>();
- params.put(GRANT_TYPE_PARAMETER, REFRESH_TOKEN_GRANT_TYPE);
- params.put(REFRESH_TOKEN_PARAMETER, refreshTokenJWTString);
- params.put(CLIENT_ID_PARAMETER, URLEncoder.encode(clientId, "UTF-8"));
+ Map> params = new HashMap<>();
+ params.put(GRANT_TYPE_PARAMETER, Collections.singletonList(REFRESH_TOKEN_GRANT_TYPE));
+ params.put(REFRESH_TOKEN_PARAMETER, Collections.singletonList(refreshTokenJWTString));
+ params.put(CLIENT_ID_PARAMETER, Collections.singletonList(URLEncoder.encode(clientId, "UTF-8")));
if (clientSecret != null && !"".equals(clientSecret)) {
- params.put(CLIENT_SECRET_PARAMETER, URLEncoder.encode(clientSecret, "UTF-8"));
+ params.put(CLIENT_SECRET_PARAMETER,
+ Collections.singletonList(URLEncoder.encode(clientSecret, "UTF-8")));
}
- String queryString = params.entrySet().stream()
- .map(p -> p.getKey() + "=" + p.getValue())
- .reduce((p1, p2) -> p1 + "&" + p2).orElse("");
-
- request = GXHTTPStringRequest.newRequest(tokenURL.toString()).header("Content-Type",
- "application/x-www-form-urlencoded").withBody(queryString);
-
- safeSetAsExternalCallForOldAPI(request);
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot construct the request object correctly", e);
+ return performRequest(tokenURL, null, params);
+ } catch (UnsupportedEncodingException e) {
+ throw new KeycloakClientException("Cannot encode parameters", e);
}
- GXInboundResponse response;
- try {
- response = request.post();
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot send request correctly", e);
- }
- if (response.isSuccessResponse()) {
- try {
- return response.tryConvertStreamedContentFromJson(TokenResponse.class);
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot construct token response object correctly", e);
- }
- } else {
- throw KeycloakClientException.create("Unable to refresh token", response.getHTTPCode(),
- response.getHeaderFields()
- .getOrDefault("content-type", Collections.singletonList("unknown/unknown")).get(0),
- response.getMessage());
- }
}
@Override
- public TokenResponse exchangeTokenForAccessToken(String context, TokenResponse oidcTokenResponse, String clientId,
+ public TokenResponse exchangeTokenForAccessToken(String context, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException {
- return exchangeTokenForAccessToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
+ return exchangeTokenForAccessToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcAccessToken, clientId,
clientSecret, audience);
}
@Override
- public TokenResponse exchangeTokenForAccessToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
+ public TokenResponse exchangeTokenForAccessToken(URL tokenURL, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException {
- return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
- ACCESS_TOKEN_TOKEN_TYPE, null);
+ return exchangeToken(tokenURL, oidcAccessToken, clientId, clientSecret, audience, ACCESS_TOKEN_TOKEN_TYPE,
+ null);
}
@Override
- public TokenResponse exchangeTokenForRefreshToken(String context, TokenResponse oidcTokenResponse, String clientId,
+ public TokenResponse exchangeTokenForRefreshToken(String context, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException {
- return exchangeTokenForRefreshToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
+ return exchangeTokenForRefreshToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcAccessToken, clientId,
clientSecret, audience);
}
@Override
- public TokenResponse exchangeTokenForRefreshToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
+ public TokenResponse exchangeTokenForRefreshToken(URL tokenURL, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException {
- return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
- REFRESH_TOKEN_TOKEN_TYPE, null);
+ return exchangeToken(tokenURL, oidcAccessToken, clientId, clientSecret, audience, REFRESH_TOKEN_TOKEN_TYPE,
+ null);
}
@Override
- public TokenResponse exchangeTokenForOfflineToken(String context, TokenResponse oidcTokenResponse, String clientId,
+ public TokenResponse exchangeTokenForOfflineToken(String context, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException {
- return exchangeTokenForOfflineToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcTokenResponse, clientId,
+ return exchangeTokenForOfflineToken(getTokenEndpointURL(getRealmBaseURL(context)), oidcAccessToken, clientId,
clientSecret, audience);
}
@Override
- public TokenResponse exchangeTokenForOfflineToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
- String clientSecret, String audience) throws KeycloakClientException {
+ public TokenResponse exchangeTokenForOfflineToken(URL tokenURL, String oidcAccessToken, String clientId,
+ String clientSecret, String audience) throws IllegalArgumentException, KeycloakClientException {
- return exchangeToken(tokenURL, oidcTokenResponse.getAccessToken(), clientId, clientSecret, audience,
- REFRESH_TOKEN_TOKEN_TYPE, OFFLINE_ACCESS_SCOPE);
+ // ModelUtils.getAccessTokenFrom(oidcTokenResponse).getScope().
+ return exchangeToken(tokenURL, oidcAccessToken, clientId, clientSecret, audience, REFRESH_TOKEN_TOKEN_TYPE,
+ OFFLINE_ACCESS_SCOPE);
}
- @Override
- public TokenResponse exchangeToken(URL tokenURL, String oidcAccessToken, String clientId, String clientSecret,
+ protected TokenResponse exchangeToken(URL tokenURL, String oidcAccessToken, String clientId, String clientSecret,
String audience, String requestedTokenType, String scope) throws KeycloakClientException {
if (audience == null || "".equals(audience)) {
@@ -658,7 +737,7 @@ public class DefaultKeycloakClient implements KeycloakClient {
logger.error("Can't URL encode audience: {}", audience, e);
}
- return performRequest(tokenURL, Collections.emptyMap(), params);
+ return performRequest(tokenURL, null, params);
}
/**
@@ -699,44 +778,9 @@ public class DefaultKeycloakClient implements KeycloakClient {
logger.debug("Verifying access token against Keycloak server with URL: {}", introspectionURL);
- // Constructing request object
- GXHTTPStringRequest request;
- try {
- Map params = new HashMap<>();
- params.put(TOKEN_PARAMETER, accessTokenJWTString);
-
- String queryString = params.entrySet().stream()
- .map(p -> p.getKey() + "=" + p.getValue())
- .reduce((p1, p2) -> p1 + "&" + p2).orElse("");
-
- request = GXHTTPStringRequest.newRequest(introspectionURL.toString()).header("Content-Type",
- "application/x-www-form-urlencoded").withBody(queryString);
-
- safeSetAsExternalCallForOldAPI(request);
-
- request = request.header("Authorization", constructBasicAuthenticationHeader(clientId, clientSecret));
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot construct the request object correctly", e);
- }
-
- GXInboundResponse response;
- try {
- response = request.post();
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot send request correctly", e);
- }
- if (response.isSuccessResponse()) {
- try {
- return response.tryConvertStreamedContentFromJson(TokenIntrospectionResponse.class);
- } catch (Exception e) {
- throw new KeycloakClientException("Cannot construct introspection response object correctly", e);
- }
- } else {
- throw KeycloakClientException.create("Unable to get token introspection response", response.getHTTPCode(),
- response.getHeaderFields()
- .getOrDefault("content-type", Collections.singletonList("unknown/unknown")).get(0),
- response.getMessage());
- }
+ return performRequest(TokenIntrospectionResponse.class, introspectionURL,
+ Collections.singletonMap("Authorization", constructBasicAuthenticationHeader(clientId, clientSecret)),
+ Collections.singletonMap(TOKEN_PARAMETER, Collections.singletonList(accessTokenJWTString)));
}
@Override
diff --git a/src/main/java/org/gcube/common/keycloak/KeycloakClient.java b/src/main/java/org/gcube/common/keycloak/KeycloakClient.java
index 8db0c32..a3aad44 100644
--- a/src/main/java/org/gcube/common/keycloak/KeycloakClient.java
+++ b/src/main/java/org/gcube/common/keycloak/KeycloakClient.java
@@ -4,6 +4,7 @@ import java.net.URL;
import java.util.List;
import java.util.Map;
+import org.gcube.common.keycloak.model.PublishedRealmRepresentation;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
@@ -72,7 +73,16 @@ public interface KeycloakClient {
* @return the Keycloak avatar
endpoint URL
* @throws KeycloakClientException if something goes wrong discovering the endpoint URL
*/
- public URL getAvatarEndpointURL(URL realmBaseURL) throws KeycloakClientException;
+ URL getAvatarEndpointURL(URL realmBaseURL) throws KeycloakClientException;
+
+ /**
+ * Get the realm info setup
+ *
+ * @param realmURL the realm URL
+ * @return the configured realm info
+ * @throws KeycloakClientException
+ */
+ PublishedRealmRepresentation getRealmInfo(URL realmURL) throws KeycloakClientException;
/**
* Queries an OIDC token from the context's Keycloak server, by using provided clientId and client secret.
@@ -85,9 +95,93 @@ public interface KeycloakClient {
*/
TokenResponse queryOIDCToken(String context, String clientId, String clientSecret) throws KeycloakClientException;
+ /**
+ * Queries an OIDC token from the context's Keycloak server, by using provided clientId and client secret.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(String context, String clientId, String clientSecret, Map extraHeaders) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret.
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret, Map extraHeaders) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(String context, String authorization) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(String context, String authorization, Map extraHeaders) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization.
+ *
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(URL tokenURL, String authorization) throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @return the issued token as {@link TokenResponse} object
+ * @throws KeycloakClientException if something goes wrong performing the query
+ */
+ TokenResponse queryOIDCToken(URL tokenURL, String authorization, Map extraHeaders) throws KeycloakClientException;
+
/**
* Queries an OIDC token from the context's Keycloak server, by using provided clientId and client secret, reducing the audience to the requested one.
*
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
* @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
* @param clientId the client id
* @param clientSecret the client secret
@@ -98,6 +192,109 @@ public interface KeycloakClient {
TokenResponse queryOIDCTokenWithContext(String context, String clientId, String clientSecret, String audience)
throws KeycloakClientException;
+ /**
+ * Queries an OIDC token from the context's Keycloak server, by using provided clientId and client secret, reducing the audience to the requested one.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders)
+ throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret, reducing the audience to the requested one.
+ *
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @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;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret, reducing the audience to the requested one.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders)
+ throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @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;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders)
+ throws KeycloakClientException;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
+ *
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @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;
+
+ /**
+ * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders)
+ 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.
*
@@ -113,87 +310,20 @@ public interface KeycloakClient {
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.
+ * 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.
+ * Optionally extra HTTP headers can be provided to be used in the call.
*
- * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
* @param clientId the client id
* @param clientSecret the client secret
* @param username the user's username
* @param password the user's password
- * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
* @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;
-
- public TokenResponse queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret,
- String username, String password, String audience, Map extraHeaders) throws KeycloakClientException;
-
- /**
- * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret.
- *
- * @param tokenURL the token endpoint {@link URL} of the Keycloak server
- * @param clientId the client id
- * @param clientSecret the client secret
- * @return the issued token as {@link TokenResponse} object
- * @throws KeycloakClientException if something goes wrong performing the query
- */
- TokenResponse queryOIDCToken(URL tokenURL, String clientId, String clientSecret) throws KeycloakClientException;
-
- /**
- * Queries an OIDC token from the Keycloak server, by using provided clientId and client secret, reducing the audience to the requested one.
- *
- * @param tokenURL the token endpoint {@link URL} of the Keycloak server
- * @param clientId the client id
- * @param clientSecret the client secret
- * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
- * @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;
-
- /**
- * 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.
- *
- * @param tokenURL the token endpoint {@link URL} of the Keycloak server
- * @param clientId the client id
- * @param clientSecret the client secret
- * @param username the user's username
- * @param password the user's password
- * @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;
-
- public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String clientId, String clientSecret,
- String username, String password, String audience, Map extraHeaders) throws KeycloakClientException;
-
- /**
- * Queries an OIDC token from the Keycloak server, by using provided authorization.
- *
- * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
- * @param tokenUrl the token endpoint {@link URL} of the OIDC server
- * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
- * @return the issued token as {@link TokenResponse} object
- * @throws KeycloakClientException if something goes wrong performing the query
- */
- TokenResponse queryOIDCToken(String context, String authorization) throws KeycloakClientException;
-
- /**
- * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
- *
- * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
- * @param tokenUrl the token endpoint {@link URL} of the OIDC server
- * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
- * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
- * @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 queryOIDCTokenOfUser(String context, String clientId, String clientSecret, String username,
+ String password, Map extraHeaders) 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.
@@ -209,30 +339,91 @@ public interface KeycloakClient {
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 extraHeaders) throws KeycloakClientException;
-
/**
- * Queries an OIDC token from the Keycloak server, by using provided authorization.
+ * 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.
*
- * @param tokenUrl the token endpoint {@link URL} of the OIDC server
- * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
- * @return the issued token as {@link TokenResponse} object
- * @throws KeycloakClientException if something goes wrong performing the query
- */
- TokenResponse queryOIDCToken(URL tokenURL, String authorization) throws KeycloakClientException;
-
- /**
- * Queries an OIDC token from the Keycloak server, by using provided authorization, reducing the audience to the requested one.
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
*
- * @param tokenUrl the token endpoint {@link URL} of the OIDC server
- * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param username the user's username
+ * @param password the user's password
* @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
* @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 queryOIDCTokenOfUserWithContext(String context, String clientId, String clientSecret, String username,
+ String password, String audience) 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.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param username the user's username
+ * @param password the user's password
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders) 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.
+ *
+ * The implementation uses the custom X-D4Science-Context
HTTP header that the proper mapper on Keycloak uses to reduce the audience
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param username the user's username
+ * @param password the user's password
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @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;
+
+ /**
+ * 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.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param tokenURL the token endpoint {@link URL} of the Keycloak server
+ * @param clientId the client id
+ * @param clientSecret the client secret
+ * @param username the user's username
+ * @param password the user's password
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders) 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.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param context the context where the Keycloak's is needed (e.g. /gcube
for DEV)
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param username the user's username
+ * @param password the user's password
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders) 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.
@@ -248,7 +439,20 @@ public interface KeycloakClient {
TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username, String password,
String audience) throws KeycloakClientException;
- public TokenResponse queryOIDCTokenOfUserWithContext(URL tokenURL, String authorization, String username,
+ /**
+ * 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.
+ * Optionally extra HTTP headers can be provided to be used in the call.
+ *
+ * @param tokenUrl the token endpoint {@link URL} of the OIDC server
+ * @param authorization the authorization to be set as header (e.g. a "Basic ...." auth or an encoded JWT access token preceded by the "Bearer " string)
+ * @param username the user's username
+ * @param password the user's password
+ * @param audience an optional parameter to shrink the token's audience to the requested one (e.g. a specific context), by leveraging on the custom HTTP header and corresponding mapper on Keycloak
+ * @param extraHeaders extra HTTP headers to add to the request
+ * @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, Map extraHeaders) throws KeycloakClientException;
/**
@@ -420,27 +624,24 @@ public interface KeycloakClient {
*/
TokenResponse refreshToken(URL tokenURL, String clientId, String clientSecret, String refreshTokenJWTString)
throws KeycloakClientException;
-
- TokenResponse exchangeTokenForOfflineToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
+
+ TokenResponse exchangeTokenForAccessToken(URL tokenURL, String oidcAccessToken, String clientId,
+ String clientSecret, String audience) throws KeycloakClientException;
+
+ TokenResponse exchangeTokenForAccessToken(String context, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException;
- TokenResponse exchangeTokenForOfflineToken(String context, TokenResponse oidcTokenResponse, String clientId,
+ TokenResponse exchangeTokenForRefreshToken(URL tokenURL, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException;
- TokenResponse exchangeTokenForRefreshToken(URL tokenURL, TokenResponse oidcTokenResponse, String clientId,
+ TokenResponse exchangeTokenForRefreshToken(String context, String oidcAccessToken, String clientId,
String clientSecret, String audience) throws KeycloakClientException;
- TokenResponse exchangeTokenForRefreshToken(String context, TokenResponse oidcTokenResponse, String clientId,
- String clientSecret, String audience) throws KeycloakClientException;
+ TokenResponse exchangeTokenForOfflineToken(URL tokenURL, String oidcAccessToken, String clientId,
+ String clientSecret, String audience) throws IllegalArgumentException, 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;
+ TokenResponse exchangeTokenForOfflineToken(String context, String oidcAccessToken, String clientId,
+ String clientSecret, String audience) throws IllegalArgumentException, KeycloakClientException;
/**
* Introspects an access token against the Keycloak server.
@@ -494,8 +695,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;
+ byte[] getAvatarData(String context, TokenResponse tokenResponse) throws KeycloakClientException;
- public byte[] getAvatarData(URL avatarURL, TokenResponse tokenResponse) throws KeycloakClientException;
+ byte[] getAvatarData(URL avatarURL, TokenResponse tokenResponse) throws KeycloakClientException;
}
\ No newline at end of file
diff --git a/src/main/java/org/gcube/common/keycloak/model/AccessToken.java b/src/main/java/org/gcube/common/keycloak/model/AccessToken.java
index bcab683..d2715d6 100644
--- a/src/main/java/org/gcube/common/keycloak/model/AccessToken.java
+++ b/src/main/java/org/gcube/common/keycloak/model/AccessToken.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
import java.io.Serializable;
@@ -10,6 +26,9 @@ import java.util.Set;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
+/**
+ * @author Bill Burke
+ */
public class AccessToken extends IDToken {
private static final long serialVersionUID = 6364784008775737335L;
@@ -156,4 +175,12 @@ public class AccessToken extends IDToken {
this.trustedCertificates = trustedCertificates;
}
+ public String getScope() {
+ return scope;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
}
diff --git a/src/main/java/org/gcube/common/keycloak/model/AddressClaimSet.java b/src/main/java/org/gcube/common/keycloak/model/AddressClaimSet.java
index ffe077d..2bf1fe6 100644
--- a/src/main/java/org/gcube/common/keycloak/model/AddressClaimSet.java
+++ b/src/main/java/org/gcube/common/keycloak/model/AddressClaimSet.java
@@ -1,7 +1,26 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
+/**
+ * @author Bill Burke
+ */
public class AddressClaimSet {
public static final String FORMATTED = "formatted";
diff --git a/src/main/java/org/gcube/common/keycloak/model/IDToken.java b/src/main/java/org/gcube/common/keycloak/model/IDToken.java
index 85256cc..ed06935 100644
--- a/src/main/java/org/gcube/common/keycloak/model/IDToken.java
+++ b/src/main/java/org/gcube/common/keycloak/model/IDToken.java
@@ -1,7 +1,26 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
+/**
+ * @author Bill Burke
+ */
public class IDToken extends JsonWebToken {
private static final long serialVersionUID = 8406175387651749097L;
diff --git a/src/main/java/org/gcube/common/keycloak/model/JsonWebToken.java b/src/main/java/org/gcube/common/keycloak/model/JsonWebToken.java
index 2b1458a..cdda20b 100644
--- a/src/main/java/org/gcube/common/keycloak/model/JsonWebToken.java
+++ b/src/main/java/org/gcube/common/keycloak/model/JsonWebToken.java
@@ -15,6 +15,9 @@ import org.gcube.common.keycloak.model.util.StringOrArrayDeserializer;
import org.gcube.common.keycloak.model.util.StringOrArraySerializer;
import org.gcube.common.keycloak.model.util.Time;
+/**
+ * @author Bill Burke
+ */
public class JsonWebToken implements Serializable {
private static final long serialVersionUID = -8136409077130940942L;
diff --git a/src/main/java/org/gcube/common/keycloak/model/ModelUtils.java b/src/main/java/org/gcube/common/keycloak/model/ModelUtils.java
index 188729e..6d66904 100644
--- a/src/main/java/org/gcube/common/keycloak/model/ModelUtils.java
+++ b/src/main/java/org/gcube/common/keycloak/model/ModelUtils.java
@@ -1,5 +1,8 @@
package org.gcube.common.keycloak.model;
+import java.security.KeyFactory;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
@@ -11,6 +14,14 @@ import org.gcube.com.fasterxml.jackson.databind.ObjectWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.JWTVerifier;
+
+/**
+ * @author Mauro Mugnaini
+ */
public class ModelUtils {
protected static final Logger logger = LoggerFactory.getLogger(ModelUtils.class);
@@ -37,6 +48,46 @@ public class ModelUtils {
}
}
+ public static RSAPublicKey createRSAPublicKey(String publicKeyPem) {
+ try {
+ String publicKey = publicKeyPem.replaceFirst("-----BEGIN .+-----\n", "");
+ publicKey = publicKey.replaceFirst("-----END .+-----", "");
+
+ byte[] encoded = Base64.getDecoder().decode(publicKey);
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ return (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
+ } catch (Exception e) {
+ throw new RuntimeException("Cant' create RSA public key from PEM string", e);
+ }
+ }
+
+ /**
+ * Verifies the token's digital signature
+ *
+ * @param token the base64 JWT token string
+ * @param publicKey the realm's public key on server
+ * @return true
if the signature is verified, false
otherwise
+ * @throws RuntimeException if an error occurs constructing the digital signature verifier
+ */
+ public static boolean isSignatureValid(String token, RSAPublicKey publicKey) throws RuntimeException {
+ JWTVerifier verifier = null;
+ try {
+ Algorithm algorithm = Algorithm.RSA256(publicKey, null);
+ verifier = JWT.require(algorithm).build();
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot construct the JWT digital signature verifier", e);
+ }
+ try {
+ verifier.verify(token);
+ return true;
+ } catch (JWTVerificationException e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("JWT digital signature is not verified", e);
+ }
+ return false;
+ }
+ }
+
public static String getAccessTokenPayloadJSONStringFrom(TokenResponse tokenResponse) throws Exception {
return getAccessTokenPayloadJSONStringFrom(tokenResponse, true);
}
diff --git a/src/main/java/org/gcube/common/keycloak/model/OIDCConstants.java b/src/main/java/org/gcube/common/keycloak/model/OIDCConstants.java
index 87298b1..079d548 100644
--- a/src/main/java/org/gcube/common/keycloak/model/OIDCConstants.java
+++ b/src/main/java/org/gcube/common/keycloak/model/OIDCConstants.java
@@ -1,5 +1,8 @@
package org.gcube.common.keycloak.model;
+/**
+ * @author Mauro Mugnaini
+ */
public class OIDCConstants {
public static final String PERMISSION_PARAMETER = "permission";
diff --git a/src/main/java/org/gcube/common/keycloak/model/PublishedRealmRepresentation.java b/src/main/java/org/gcube/common/keycloak/model/PublishedRealmRepresentation.java
new file mode 100644
index 0000000..c86b862
--- /dev/null
+++ b/src/main/java/org/gcube/common/keycloak/model/PublishedRealmRepresentation.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
+
+import java.security.interfaces.RSAPublicKey;
+
+import org.gcube.com.fasterxml.jackson.annotation.JsonIgnore;
+import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author Bill Burke
+ * @author (modified by) Mauro Mugnaini
+ */
+public class PublishedRealmRepresentation {
+ protected String realm;
+
+ @JsonProperty("public_key")
+ protected String publicKeyPem;
+
+ @JsonProperty("token-service")
+ protected String tokenServiceUrl;
+
+ @JsonProperty("account-service")
+ protected String accountServiceUrl;
+
+ @JsonProperty("tokens-not-before")
+ protected int notBefore;
+
+ @JsonIgnore
+ protected volatile transient RSAPublicKey publicKey;
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public void setRealm(String realm) {
+ this.realm = realm;
+ }
+
+ public String getPublicKeyPem() {
+ return publicKeyPem;
+ }
+
+ public void setPublicKeyPem(String publicKeyPem) {
+ this.publicKeyPem = publicKeyPem;
+ this.publicKey = null;
+ }
+
+ @JsonIgnore
+ public RSAPublicKey getPublicKey() {
+ if (publicKey != null)
+ return publicKey;
+ if (publicKeyPem != null) {
+ publicKey = ModelUtils.createRSAPublicKey(publicKeyPem);
+ }
+ return publicKey;
+ }
+
+ @JsonIgnore
+ public void setPublicKey(RSAPublicKey publicKey) {
+ this.publicKey = publicKey;
+// this.publicKeyPem = PemUtils.encodeKey(publicKey);
+ }
+
+ public String getTokenServiceUrl() {
+ return tokenServiceUrl;
+ }
+
+ public void setTokenServiceUrl(String tokenServiceUrl) {
+ this.tokenServiceUrl = tokenServiceUrl;
+ }
+
+ public String getAccountServiceUrl() {
+ return accountServiceUrl;
+ }
+
+ public void setAccountServiceUrl(String accountServiceUrl) {
+ this.accountServiceUrl = accountServiceUrl;
+ }
+
+ public int getNotBefore() {
+ return notBefore;
+ }
+
+ public void setNotBefore(int notBefore) {
+ this.notBefore = notBefore;
+ }
+}
diff --git a/src/main/java/org/gcube/common/keycloak/model/RefreshToken.java b/src/main/java/org/gcube/common/keycloak/model/RefreshToken.java
index 2ee8115..f6b21cc 100644
--- a/src/main/java/org/gcube/common/keycloak/model/RefreshToken.java
+++ b/src/main/java/org/gcube/common/keycloak/model/RefreshToken.java
@@ -1,5 +1,24 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
+/**
+ * @author Bill Burke
+ */
public class RefreshToken extends AccessToken {
private static final long serialVersionUID = 2646534143077862960L;
diff --git a/src/main/java/org/gcube/common/keycloak/model/TokenIntrospectionResponse.java b/src/main/java/org/gcube/common/keycloak/model/TokenIntrospectionResponse.java
index 814f837..eb72d00 100644
--- a/src/main/java/org/gcube/common/keycloak/model/TokenIntrospectionResponse.java
+++ b/src/main/java/org/gcube/common/keycloak/model/TokenIntrospectionResponse.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
import java.util.List;
@@ -5,6 +21,9 @@ import java.util.List;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
import org.gcube.common.keycloak.model.idm.authorization.Permission;
+/**
+ * @author Pedro Igor
+ */
public class TokenIntrospectionResponse extends JsonWebToken {
private static final long serialVersionUID = -3105799239959636906L;
diff --git a/src/main/java/org/gcube/common/keycloak/model/TokenResponse.java b/src/main/java/org/gcube/common/keycloak/model/TokenResponse.java
index bf502fd..8d5fe97 100644
--- a/src/main/java/org/gcube/common/keycloak/model/TokenResponse.java
+++ b/src/main/java/org/gcube/common/keycloak/model/TokenResponse.java
@@ -10,6 +10,9 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * @author Mauro Mugnaini
+ */
public class TokenResponse implements Serializable {
protected static Logger logger = LoggerFactory.getLogger(TokenResponse.class);
diff --git a/src/main/java/org/gcube/common/keycloak/model/UserInfo.java b/src/main/java/org/gcube/common/keycloak/model/UserInfo.java
index b3bfb9d..4f1ea83 100644
--- a/src/main/java/org/gcube/common/keycloak/model/UserInfo.java
+++ b/src/main/java/org/gcube/common/keycloak/model/UserInfo.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model;
import java.util.HashMap;
diff --git a/src/main/java/org/gcube/common/keycloak/model/idm/authorization/Permission.java b/src/main/java/org/gcube/common/keycloak/model/idm/authorization/Permission.java
index ef7a7ae..dcc91d9 100644
--- a/src/main/java/org/gcube/common/keycloak/model/idm/authorization/Permission.java
+++ b/src/main/java/org/gcube/common/keycloak/model/idm/authorization/Permission.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model.idm.authorization;
import java.util.HashSet;
@@ -9,6 +25,9 @@ import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.gcube.com.fasterxml.jackson.annotation.JsonInclude;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
+/**
+ * @author Pedro Igor
+ */
@JsonIgnoreProperties(ignoreUnknown = true)
public class Permission {
diff --git a/src/main/java/org/gcube/common/keycloak/model/util/StringListMapDeserializer.java b/src/main/java/org/gcube/common/keycloak/model/util/StringListMapDeserializer.java
index d399eff..751c12e 100644
--- a/src/main/java/org/gcube/common/keycloak/model/util/StringListMapDeserializer.java
+++ b/src/main/java/org/gcube/common/keycloak/model/util/StringListMapDeserializer.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model.util;
import java.io.IOException;
diff --git a/src/main/java/org/gcube/common/keycloak/model/util/StringOrArrayDeserializer.java b/src/main/java/org/gcube/common/keycloak/model/util/StringOrArrayDeserializer.java
index 6eb1450..ec1e642 100644
--- a/src/main/java/org/gcube/common/keycloak/model/util/StringOrArrayDeserializer.java
+++ b/src/main/java/org/gcube/common/keycloak/model/util/StringOrArrayDeserializer.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model.util;
import java.io.IOException;
diff --git a/src/main/java/org/gcube/common/keycloak/model/util/StringOrArraySerializer.java b/src/main/java/org/gcube/common/keycloak/model/util/StringOrArraySerializer.java
index 386ec5d..0950367 100644
--- a/src/main/java/org/gcube/common/keycloak/model/util/StringOrArraySerializer.java
+++ b/src/main/java/org/gcube/common/keycloak/model/util/StringOrArraySerializer.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model.util;
import java.io.IOException;
diff --git a/src/main/java/org/gcube/common/keycloak/model/util/Time.java b/src/main/java/org/gcube/common/keycloak/model/util/Time.java
index 1101d1a..71b266e 100644
--- a/src/main/java/org/gcube/common/keycloak/model/util/Time.java
+++ b/src/main/java/org/gcube/common/keycloak/model/util/Time.java
@@ -1,7 +1,26 @@
+/*
+ * Copyright 2016 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.gcube.common.keycloak.model.util;
import java.util.Date;
+/**
+ * @author Stian Thorgersen
+ */
public class Time {
private static int offset;
diff --git a/src/test/java/org/gcube/common/keycloak/TestKeycloakClient.java b/src/test/java/org/gcube/common/keycloak/TestKeycloakClient.java
index 4d31847..dbf7145 100644
--- a/src/test/java/org/gcube/common/keycloak/TestKeycloakClient.java
+++ b/src/test/java/org/gcube/common/keycloak/TestKeycloakClient.java
@@ -6,6 +6,7 @@ import java.net.URL;
import java.util.Collections;
import org.gcube.common.keycloak.model.ModelUtils;
+import org.gcube.common.keycloak.model.PublishedRealmRepresentation;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
import org.junit.After;
@@ -124,6 +125,34 @@ public class TestKeycloakClient {
Assert.assertEquals(customBase + KeycloakClient.DEFAULT_REALM + "/", customBaseURL.toString());
}
+ @Test
+ public void test10QueryRealmInfo() throws Exception {
+ logger.info("*** [1.0] Start testing query realm info...");
+ KeycloakClient client = KeycloakClientFactory.newInstance();
+ PublishedRealmRepresentation realmInfo = client.getRealmInfo(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
+
+ logger.info("*** [1.0] Realm info public key PEM: {}", realmInfo.getPublicKeyPem());
+ logger.info("*** [1.0] Realm info public key: {}", realmInfo.getPublicKey());
+ // TestModels.checkTokenResponse(oidcTR);
+ // TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), "service-account-" + CLIENT_ID, false);
+ }
+
+ @Test
+ public void test11TestAccessTokenJWTSignature() throws Exception {
+ logger.info("*** [1.0] Start testing access token JTW signature with model utils...");
+ KeycloakClient client = KeycloakClientFactory.newInstance();
+ PublishedRealmRepresentation realmInfo = client.getRealmInfo(client.getRealmBaseURL(DEV_ROOT_CONTEXT));
+
+ logger.info("*** [1.0] Realm info public key PEM: {}", realmInfo.getPublicKeyPem());
+ logger.info("*** [1.0] Realm info public key: {}", realmInfo.getPublicKey());
+
+ TokenResponse oidcTR = client.queryOIDCToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET);
+ logger.info("*** [1.0] OIDC access token: {}", oidcTR.getAccessToken());
+
+ Assert.assertTrue("Access token digital signature is not valid",
+ ModelUtils.isSignatureValid(oidcTR.getAccessToken(), realmInfo.getPublicKey()));
+ }
+
@Test
public void test12QueryOIDCToken() throws Exception {
logger.info("*** [1.2] Start testing query OIDC token from Keycloak with context...");
@@ -132,8 +161,8 @@ public class TestKeycloakClient {
logger.info("*** [1.2] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.2] OIDC refresh token: {}", oidcTR.getRefreshToken());
- TestModels.checkTokenResponse(oidcTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), "service-account-" + CLIENT_ID, false);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), "service-account-" + CLIENT_ID, false);
}
@Test
@@ -145,8 +174,8 @@ public class TestKeycloakClient {
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);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), "service-account-" + CLIENT_ID, false);
}
@Test
@@ -157,8 +186,8 @@ public class TestKeycloakClient {
logger.info("*** [1.3] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.3] OIDC refresh token: {}", oidcTR.getRefreshToken());
- TestModels.checkTokenResponse(oidcTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, false);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, false);
}
@Test
@@ -169,8 +198,8 @@ public class TestKeycloakClient {
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);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.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,
@@ -178,10 +207,10 @@ public class TestKeycloakClient {
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);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkTokenResponse(oidcRestrictedTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcRestrictedTR), TEST_USER_USERNAME, true);
assertTrue(ModelUtils.getAccessTokenFrom(oidcTR).getAudience().length > 1);
assertTrue(ModelUtils.getAccessTokenFrom(oidcRestrictedTR).getAudience().length == 1);
assertTrue(
@@ -197,16 +226,16 @@ public class TestKeycloakClient {
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);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, false);
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());
- TestModels.checkTokenResponse(umaTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), TEST_USER_USERNAME, true);
+ TestModelUtils.checkTokenResponse(umaTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), TEST_USER_USERNAME, true);
}
@Test
@@ -220,8 +249,8 @@ public class TestKeycloakClient {
logger.info("*** [1.3c] OIDC access token: {}", oidcTR.getAccessToken());
logger.info("*** [1.3c] OIDC refresh token: {}", oidcTR.getRefreshToken());
- TestModels.checkTokenResponse(oidcTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
+ TestModelUtils.checkTokenResponse(oidcTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(oidcTR), TEST_USER_USERNAME, true);
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.
}
@@ -235,8 +264,8 @@ public class TestKeycloakClient {
logger.info("*** [2.4] UMA access token: {}", umaTR.getAccessToken());
logger.info("*** [2.4] UMA refresh token: {}", umaTR.getRefreshToken());
- TestModels.checkTokenResponse(umaTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), "service-account-" + CLIENT_ID, true);
+ TestModelUtils.checkTokenResponse(umaTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), "service-account-" + CLIENT_ID, true);
}
@Test
@@ -249,8 +278,8 @@ public class TestKeycloakClient {
logger.info("*** [2.4a] UMA access token: {}", umaTR.getAccessToken());
logger.info("*** [2.4a] UMA refresh token: {}", umaTR.getRefreshToken());
- TestModels.checkTokenResponse(umaTR);
- TestModels.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), "service-account-" + CLIENT_ID, true);
+ TestModelUtils.checkTokenResponse(umaTR);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(umaTR), "service-account-" + CLIENT_ID, true);
}
@Test
@@ -262,7 +291,7 @@ public class TestKeycloakClient {
TokenIntrospectionResponse tir = client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
oidcTR.getAccessToken());
- TestModels.checkTokenIntrospectionResponse(tir);
+ TestModelUtils.checkTokenIntrospectionResponse(tir);
}
@Test
@@ -275,7 +304,7 @@ public class TestKeycloakClient {
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
oidcTR.getAccessToken());
- TestModels.checkTokenIntrospectionResponse(tir);
+ TestModelUtils.checkTokenIntrospectionResponse(tir);
}
@Test
@@ -291,7 +320,7 @@ public class TestKeycloakClient {
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
oidcTR.getAccessToken());
- TestModels.checkTokenIntrospectionResponse(tir, true);
+ TestModelUtils.checkTokenIntrospectionResponse(tir, true);
}
@Test
@@ -302,7 +331,7 @@ public class TestKeycloakClient {
TokenIntrospectionResponse tir = client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET,
umaTR.getAccessToken());
- TestModels.checkTokenIntrospectionResponse(tir);
+ TestModelUtils.checkTokenIntrospectionResponse(tir);
}
@Test
@@ -314,7 +343,7 @@ public class TestKeycloakClient {
TokenIntrospectionResponse tir = client.introspectAccessToken(introspectionURL, CLIENT_ID, CLIENT_SECRET,
umaTR.getAccessToken());
- TestModels.checkTokenIntrospectionResponse(tir);
+ TestModelUtils.checkTokenIntrospectionResponse(tir);
}
@Test
@@ -398,8 +427,8 @@ public class TestKeycloakClient {
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);
+ TestModelUtils.checkTokenResponse(tokenResponse);
+ TestModelUtils.checkAccessToken(ModelUtils.getAccessTokenFrom(tokenResponse), TEST_USER_USERNAME, true);
}
@Test
@@ -407,19 +436,18 @@ public class TestKeycloakClient {
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);
+ 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);
+ TokenResponse exchangedTR = client.exchangeTokenForAccessToken(DEV_ROOT_CONTEXT, oidcTR.getAccessToken(),
+ CLIENT_ID, CLIENT_SECRET, CLIENT_ID);
logger.info("*** [5.1] Exchanged access token: {}", exchangedTR.getAccessToken());
- TestModels.checkTokenResponse(exchangedTR, false);
+ TestModelUtils.checkTokenResponse(exchangedTR, false);
Assert.assertNull(exchangedTR.getRefreshToken());
- TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
+ TestModelUtils.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET, exchangedTR.getAccessToken()));
}
@@ -436,14 +464,14 @@ public class TestKeycloakClient {
logger.info("*** [5.1a] UMA access token: {}", umaTR.getAccessToken());
- TokenResponse exchangedTR = client.exchangeTokenForAccessToken(DEV_ROOT_CONTEXT, umaTR, CLIENT_ID,
- CLIENT_SECRET, CLIENT_ID);
+ TokenResponse exchangedTR = client.exchangeTokenForAccessToken(DEV_ROOT_CONTEXT, umaTR.getAccessToken(),
+ CLIENT_ID, CLIENT_SECRET, CLIENT_ID);
logger.info("*** [5.1a] Exchanged access token: {}", exchangedTR.getAccessToken());
- TestModels.checkTokenResponse(exchangedTR, false);
+ TestModelUtils.checkTokenResponse(exchangedTR, false);
Assert.assertNull(exchangedTR.getRefreshToken());
- TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
+ TestModelUtils.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
CLIENT_SECRET, exchangedTR.getAccessToken()));
}
@@ -456,14 +484,14 @@ public class TestKeycloakClient {
logger.info("*** [5.2] OIDC access token: {}", oidcTR.getAccessToken());
- TokenResponse exchangedTR = client.exchangeTokenForRefreshToken(DEV_ROOT_CONTEXT, oidcTR, CLIENT_ID,
- CLIENT_SECRET, CLIENT_ID);
+ TokenResponse exchangedTR = client.exchangeTokenForRefreshToken(DEV_ROOT_CONTEXT, oidcTR.getAccessToken(),
+ 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);
+ TestModelUtils.checkTokenResponse(exchangedTR);
- TestModels.checkTokenIntrospectionResponse(
+ TestModelUtils.checkTokenIntrospectionResponse(
client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID, CLIENT_SECRET, exchangedTR.getAccessToken()));
}
@@ -472,31 +500,32 @@ public class TestKeycloakClient {
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);
+ 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);
+ TokenResponse exchangedTR = client.exchangeTokenForOfflineToken(DEV_ROOT_CONTEXT, oidcTR.getAccessToken(),
+ 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);
+ TestModelUtils.checkTokenResponse(exchangedTR, true);
+ TestModelUtils.checkOfflineToken(exchangedTR);
- TestModels.checkTokenIntrospectionResponse(client.introspectAccessToken(DEV_ROOT_CONTEXT, CLIENT_ID,
+ TestModelUtils.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);
- // }
+ @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, CLIENT_ID, CLIENT_SECRET,
+ 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);
+ }
}
diff --git a/src/test/java/org/gcube/common/keycloak/TestModels.java b/src/test/java/org/gcube/common/keycloak/TestModelUtils.java
similarity index 86%
rename from src/test/java/org/gcube/common/keycloak/TestModels.java
rename to src/test/java/org/gcube/common/keycloak/TestModelUtils.java
index c51b604..4a8ea2b 100644
--- a/src/test/java/org/gcube/common/keycloak/TestModels.java
+++ b/src/test/java/org/gcube/common/keycloak/TestModelUtils.java
@@ -1,6 +1,8 @@
package org.gcube.common.keycloak;
import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
import org.gcube.common.keycloak.model.AccessToken;
@@ -18,9 +20,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class TestModels {
+public class TestModelUtils {
- protected static final Logger logger = LoggerFactory.getLogger(TestModels.class);
+ protected static final Logger logger = LoggerFactory.getLogger(TestModelUtils.class);
@Before
public void setUp() throws Exception {
@@ -30,6 +32,19 @@ public class TestModels {
public void tearDown() throws Exception {
}
+ @Test
+ public void testTokenDigitalSignature() throws Exception {
+ logger.info("Start testing OIDC token response object binding...");
+ TokenResponse tr = new ObjectMapper().readValue(new File("src/test/resources/oidc-token-response.json"),
+ TokenResponse.class);
+
+ // Valid signature
+ Assert.assertFalse("Token signature is valid", ModelUtils.isSignatureValid(tr.getAccessToken(),
+ ModelUtils.createRSAPublicKey(
+ new String(Files.readAllBytes(Paths.get("src/test/resources/rsa-public-key.pem"))))));
+
+ }
+
@Test
public void testTokenResponseForOIDC() throws Exception {
logger.info("Start testing OIDC token response object binding...");
@@ -38,7 +53,7 @@ public class TestModels {
logger.debug("OIDC token response:\n{}", ModelUtils.toJSONString(tr, true));
checkTokenResponse(tr);
-
+
}
@Test
@@ -112,13 +127,13 @@ public class TestModels {
public static void checkRefreshToken(RefreshToken rt) {
logger.debug("Refresh token:\n{}", ModelUtils.toJSONString(rt, true));
Assert.assertNotNull("Other claims are null", rt.getOtherClaims());
- Assert.assertNotNull("Audience is null",rt.getAudience());
+ 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());
+ Assert.assertNull("Expiration is not null", rt.getExp());
}
public static void checkTokenIntrospectionResponse(TokenIntrospectionResponse tir) {
diff --git a/src/test/resources/rsa-public-key.pem b/src/test/resources/rsa-public-key.pem
new file mode 100644
index 0000000..44e740c
--- /dev/null
+++ b/src/test/resources/rsa-public-key.pem
@@ -0,0 +1 @@
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjyJAmPx5K2eGYjvRmiBC8as3nF/jsYSUgBnlul9TNEdWSPuxTzntTb37xDGPmVRkNyOCJmRnBcI8GbrWz8SHJ643JTKp8yx4zDQCgLD72crb9ah/Tfu8KpDz3+FRuYLE4EvvRCGBnsFO2vSM02iTAp7nSToOCX4jCCrDMBUUJkIzuZIQUBTx8lvWl/M6LtQAqS7Gw3wsZSklRcvsR9qlCUxJW3cvhALt9wWrejSJ3LaR6TMaNa8k6Ojk6bJ3/5c6OifxYde0YjXIOaeMkkgnfoQvs4cyhvNxCXLx65+VKV4Dlts7cTgJvuodV0w/UhJGfUxgA9V6IQowmwHNBnYAMwIDAQAB
\ No newline at end of file