Compare commits

...

1 Commits

Author SHA1 Message Date
Lucio Lelii f232361d1f porting to smartgears 4 2022-06-15 17:58:10 +02:00
4 changed files with 203 additions and 123 deletions

View File

@ -18,7 +18,7 @@
<dependency>
<groupId>org.gcube.distribution</groupId>
<artifactId>gcube-bom</artifactId>
<version>2.0.1</version>
<version>3.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -35,7 +35,6 @@
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>keycloak-client</artifactId>
<version>[2.0.0-SNAPSHOT,)</version>
</dependency>
<dependency>

View File

@ -6,162 +6,202 @@ import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.gcube.common.keycloak.model.ModelUtils;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.security.AuthorizedTasks;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("deprecation")
public class DefaultKeycloakClientLegacyIS extends DefaultKeycloakClient implements KeycloakClientLegacyIS {
protected static Logger logger = LoggerFactory.getLogger(DefaultKeycloakClientLegacyIS.class);
protected static Logger logger = LoggerFactory.getLogger(DefaultKeycloakClientLegacyIS.class);
@Override
public URL findTokenEndpointURL() throws KeycloakClientException {
logger.debug("Checking ScopeProvider's scope presence and format");
String originalScope = ScopeProvider.instance.get();
if (originalScope == null || !originalScope.startsWith("/") || originalScope.length() < 2) {
throw new KeycloakClientException(originalScope == null ? "Scope not found in ScopeProvider"
: "Bad scope name found: " + originalScope);
}
logger.debug("Assuring use the rootVO to query the endpoint simple query. Actual scope is: {}", originalScope);
String rootVOScope = "/" + originalScope.split("/")[1];
logger.debug("Setting rootVO scope into provider as: {}", rootVOScope);
@Override
public URL findTokenEndpointURL(String audience) throws KeycloakClientException {
logger.debug("Checking ScopeProvider's scope presence and format");
String originalScope = audience;
if (originalScope == null || !originalScope.startsWith("/") || originalScope.length() < 2) {
if (SecretManagerProvider.instance.get()!=null)
originalScope = SecretManagerProvider.instance.get().getContext();
else throw new KeycloakClientException(originalScope == null ? "Scope not found in ScopeProvider"
: "Bad scope name found: " + originalScope);
}
logger.debug("Assuring use the rootVO to query the endpoint simple query. Actual scope is: {}", originalScope);
String rootVOScope = "/" + originalScope.split("/")[1];
logger.debug("Setting rootVO scope into provider as: {}", rootVOScope);
List<AccessPoint> accessPoints = null;
Callable<List<AccessPoint>> endpoints = new Callable<List<AccessPoint>>() {
@Override
public List<AccessPoint> call() throws Exception {
logger.debug("Creating simple query");
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition(
String.format("$resource/Profile/Category/text() eq '%s'", CATEGORY))
.addCondition(String.format("$resource/Profile/Name/text() eq '%s'", NAME))
.setResult(String.format("$resource/Profile/AccessPoint[Description/text() eq '%s']", DESCRIPTION));
// trying to be thread safe at least for these calls
synchronized (ScopeProvider.instance) {
boolean scopeModified = false;
if (!ScopeProvider.instance.get().equals(rootVOScope)) {
logger.debug("Overriding scope in the provider with rootVO scope : {}", rootVOScope);
ScopeProvider.instance.set(rootVOScope);
scopeModified = true;
}
logger.debug("Creating client for AccessPoint");
DiscoveryClient<AccessPoint> client = clientFor(AccessPoint.class);
logger.debug("Creating simple query");
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition(
String.format("$resource/Profile/Category/text() eq '%s'", CATEGORY))
.addCondition(String.format("$resource/Profile/Name/text() eq '%s'", NAME))
.setResult(String.format("$resource/Profile/AccessPoint[Description/text() eq '%s']", DESCRIPTION));
logger.trace("Submitting query: {}", query);
return client.submit(query);
}
};
List<AccessPoint> accessPoints = null;
try {
accessPoints= AuthorizedTasks.executeSafely( endpoints, new Secret() {
logger.debug("Creating client for AccessPoint");
DiscoveryClient<AccessPoint> client = clientFor(AccessPoint.class);
@Override
public boolean isRefreshable() {
// TODO Auto-generated method stub
return false;
}
logger.trace("Submitting query: {}", query);
accessPoints = client.submit(query);
@Override
public boolean isExpired() {
// TODO Auto-generated method stub
return false;
}
if (scopeModified) {
logger.debug("Resetting scope into provider to the original value: {}", originalScope);
ScopeProvider.instance.set(originalScope);
}
}
@Override
public Owner getOwner() {
// TODO Auto-generated method stub
return null;
}
if (accessPoints.size() == 0) {
throw new KeycloakClientException("Service endpoint not found");
} else if (accessPoints.size() > 1) {
throw new KeycloakClientException("Found more than one endpoint with query");
}
String address = accessPoints.iterator().next().address();
logger.debug("Found address: {}", address);
try {
return new URL(address);
} catch (MalformedURLException e) {
throw new KeycloakClientException("Cannot create URL from address: " + address, e);
}
}
@Override
public Map<String, String> getHTTPAuthorizationHeaders() {
// TODO Auto-generated method stub
return null;
}
@Override
public URL computeIntrospectionEndpointURL() throws KeycloakClientException {
return computeIntrospectionEndpointURL(findTokenEndpointURL());
}
@Override
public String getContext() {
return rootVOScope;
}
});
@Override
public TokenResponse queryOIDCToken(String clientId, String clientSecret) throws KeycloakClientException {
return queryOIDCToken(findTokenEndpointURL(), clientId, clientSecret);
}
}catch (Throwable e) {
throw new KeycloakClientException("error executing query to retrieve url", e);
}
@Override
public TokenResponse queryUMAToken(String clientId, String clientSecret, List<String> permissions)
throws KeycloakClientException {
return queryUMAToken(clientId, clientSecret, ScopeProvider.instance.get(), permissions);
}
@Override
public TokenResponse queryUMAToken(TokenResponse oidcTokenResponse, String audience, List<String> permissions)
throws KeycloakClientException {
if (accessPoints.size() == 0) {
throw new KeycloakClientException("Service endpoint not found");
} else if (accessPoints.size() > 1) {
throw new KeycloakClientException("Found more than one endpoint with query");
}
String address = accessPoints.iterator().next().address();
logger.debug("Found address: {}", address);
try {
return new URL(address);
} catch (MalformedURLException e) {
throw new KeycloakClientException("Cannot create URL from address: " + address, e);
}
}
@Override
public URL findTokenEndpointURL() throws KeycloakClientException {
logger.debug("Checking ScopeProvider's scope presence and format");
String originalScope = SecretManagerProvider.instance.get().getContext();
return findTokenEndpointURL(originalScope);
}
return queryUMAToken(findTokenEndpointURL(), constructBeareAuthenticationHeader(oidcTokenResponse), audience,
permissions);
}
@Override
public URL computeIntrospectionEndpointURL() throws KeycloakClientException {
return computeIntrospectionEndpointURL(findTokenEndpointURL());
}
@Override
public TokenResponse queryUMAToken(String clientId, String clientSecret, String audience,
List<String> permissions) throws KeycloakClientException {
@Override
public TokenResponse queryOIDCToken(String clientId, String clientSecret) throws KeycloakClientException {
return queryOIDCToken(findTokenEndpointURL(), clientId, clientSecret);
}
return queryUMAToken(findTokenEndpointURL(), clientId, clientSecret, audience, permissions);
}
@Override
public TokenResponse queryUMAToken(String clientId, String clientSecret, List<String> permissions)
throws KeycloakClientException {
@Override
public TokenResponse refreshToken(TokenResponse tokenResponse) throws KeycloakClientException {
return refreshToken((String) null, tokenResponse);
}
return queryUMAToken(clientId, clientSecret, SecretManagerProvider.instance.get().getContext(), permissions);
}
@Override
public TokenResponse refreshToken(String clientId, TokenResponse tokenResponse) throws KeycloakClientException {
return refreshToken(clientId, null, tokenResponse);
}
@Override
public TokenResponse queryUMAToken(TokenResponse oidcTokenResponse, String audience, List<String> permissions)
throws KeycloakClientException {
@Override
public TokenResponse refreshToken(String clientId, String clientSecret, TokenResponse tokenResponse)
throws KeycloakClientException {
return queryUMAToken(findTokenEndpointURL(audience), constructBeareAuthenticationHeader(oidcTokenResponse), audience,
permissions);
}
return refreshToken(findTokenEndpointURL(), clientId, clientSecret, tokenResponse);
}
@Override
public TokenResponse queryUMAToken(String clientId, String clientSecret, String audience,
List<String> permissions) throws KeycloakClientException {
@Override
public TokenResponse refreshToken(String refreshTokenJWTString) throws KeycloakClientException {
try {
String clientId = ModelUtils.getClientIdFromToken(ModelUtils.getRefreshTokenFrom(refreshTokenJWTString));
return refreshToken(clientId, refreshTokenJWTString);
} catch (Exception e) {
throw new KeycloakClientException("Cannot construct access token object from token response", e);
}
}
return queryUMAToken(findTokenEndpointURL(audience), clientId, clientSecret, audience, permissions);
}
@Override
public TokenResponse refreshToken(String clientId, String refreshTokenJWTString) throws KeycloakClientException {
return refreshToken(clientId, null, refreshTokenJWTString);
}
@Override
public TokenResponse refreshToken(TokenResponse tokenResponse) throws KeycloakClientException {
return refreshToken((String) null, tokenResponse);
}
@Override
public TokenResponse refreshToken(String clientId, String clientSecret, String refreshTokenJWTString)
throws KeycloakClientException {
@Override
public TokenResponse refreshToken(String clientId, TokenResponse tokenResponse) throws KeycloakClientException {
return refreshToken(clientId, null, tokenResponse);
}
return refreshToken(findTokenEndpointURL(), clientId, clientSecret, refreshTokenJWTString);
}
@Override
public TokenResponse refreshToken(String clientId, String clientSecret, TokenResponse tokenResponse)
throws KeycloakClientException {
@Override
public TokenIntrospectionResponse introspectAccessToken(String clientId, String clientSecret,
String accessTokenJWTString) throws KeycloakClientException {
return refreshToken(findTokenEndpointURL(), clientId, clientSecret, tokenResponse);
}
return introspectAccessToken(computeIntrospectionEndpointURL(), clientId, clientSecret, accessTokenJWTString);
}
@Override
public TokenResponse refreshToken(String refreshTokenJWTString) throws KeycloakClientException {
try {
String clientId = ModelUtils.getClientIdFromToken(ModelUtils.getRefreshTokenFrom(refreshTokenJWTString));
return refreshToken(clientId, refreshTokenJWTString);
} catch (Exception e) {
throw new KeycloakClientException("Cannot construct access token object from token response", e);
}
}
@Override
public boolean isAccessTokenVerified(String clientId, String clientSecret, String accessTokenJWTString)
throws KeycloakClientException {
@Override
public TokenResponse refreshToken(String clientId, String refreshTokenJWTString) throws KeycloakClientException {
return refreshToken(clientId, null, refreshTokenJWTString);
}
return isAccessTokenVerified(computeIntrospectionEndpointURL(), clientId, clientSecret, accessTokenJWTString);
}
@Override
public TokenResponse refreshToken(String clientId, String clientSecret, String refreshTokenJWTString)
throws KeycloakClientException {
return refreshToken(findTokenEndpointURL(), clientId, clientSecret, refreshTokenJWTString);
}
@Override
public TokenIntrospectionResponse introspectAccessToken(String clientId, String clientSecret,
String accessTokenJWTString) throws KeycloakClientException {
return introspectAccessToken(computeIntrospectionEndpointURL(), clientId, clientSecret, accessTokenJWTString);
}
@Override
public boolean isAccessTokenVerified(String clientId, String clientSecret, String accessTokenJWTString)
throws KeycloakClientException {
return isAccessTokenVerified(computeIntrospectionEndpointURL(), clientId, clientSecret, accessTokenJWTString);
}
}

View File

@ -5,9 +5,7 @@ import java.util.List;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
import org.gcube.common.scope.api.ScopeProvider;
@SuppressWarnings("deprecation")
public interface KeycloakClientLegacyIS extends KeycloakClient {
String CATEGORY = "Auth";
@ -22,6 +20,15 @@ public interface KeycloakClientLegacyIS extends KeycloakClient {
*/
URL findTokenEndpointURL() throws KeycloakClientException;
/**
* Finds the keycloak <code>token</code> endpoint {@link URL} discovering it in the passed audience
*
* @return the keycloak <code>token</code> endpoint URL in the current scope
* @throws KeycloakClientException if something goes wrong discovering the endpoint URL
*/
URL findTokenEndpointURL(String audience)throws KeycloakClientException;
/**
* Compute the keycloak <code>introspection</code> endpoint {@link URL} starting from the discovered token endpoint it in the current scope provided by {@link ScopeProvider}.
*

View File

@ -1,11 +1,14 @@
package org.gcube.common.keycloak;
import java.net.URL;
import java.util.Map;
import org.gcube.common.keycloak.model.ModelUtils;
import org.gcube.common.keycloak.model.TokenIntrospectionResponse;
import org.gcube.common.keycloak.model.TokenResponse;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -15,7 +18,6 @@ import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("deprecation")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestKeycloakClientLegacyIS {
@ -35,7 +37,39 @@ public class TestKeycloakClientLegacyIS {
@Before
public void setUp() throws Exception {
ScopeProvider.instance.set("/gcube");
Secret testSecret = new Secret() {
@Override
public boolean isRefreshable() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isExpired() {
// TODO Auto-generated method stub
return false;
}
@Override
public Owner getOwner() {
// TODO Auto-generated method stub
return null;
}
@Override
public Map<String, String> getHTTPAuthorizationHeaders() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getContext() {
return "/gcube";
}
};
SecretManagerProvider.instance.set(testSecret);
}
@After