working client

This commit is contained in:
Alfredo Oliviero 2024-03-19 13:59:24 +01:00
parent c5e9810fc0
commit 365716ba77
23 changed files with 1274 additions and 300 deletions

View File

@ -1,5 +1,6 @@
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java11-tomcat9
#FROM smartgears-distribution:4.0.0-java11-tomcat9-devel
ARG JAVA_VERSION=11
FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java$JAVA_VERSION-tomcat10.1.19
#FROM smartgears-distribution:4.0.0-SNAPSHOT-java$JAVA_VERSION-tomcat10.1.19
COPY ./docker/logback.xml /etc/
COPY ./docker/container.ini /etc/

View File

@ -1,5 +1,88 @@
mvn clean package
#!/bin/bash
NAME=idm
docker build -t $NAME .
docker run -p 8080:8080 $NAME
accepted_java_versions=(11 17)
NAME=identity-manager
PORT=8080
DEBUG_PORT=5005
DEBUG=false
COMPILE=true
java_version=11
################################################################################
# Help #
################################################################################
Help() {
# Display Help
echo "build, create and run in docker the identity manager service"
echo
echo "Syntax: buildDistribution [-n arg] [-p arg] [-j arg] [-d arg?] [-h]"
echo "options:"
echo "-s skip maven package"
echo "-n arg specifies the docker image name (default is identity-manager)."
echo "-p arg specifies the port to be exposed for the docker container to access the service (default $PORT)"
echo "-j arg specify java version (default is $java_version)"
echo " accepted version are: ${accepted_java_versions[@]}"
echo "-d arg? enable java debug mode"
echo " arg is the debug port (default is $DEBUG_PORT)"
echo "-h Print this Help."
echo
}
################################################################################
################################################################################
# Main program #
################################################################################
################################################################################
set -e
OPTSTRING=":sn:p:d:j:?h"
while getopts $OPTSTRING opt; do
# echo "Option -${opt} was triggered, Argument: ${OPTARG}"
case "${opt}" in
s) COMPILE=false && echo "compile $COMPILE" ;;
n) NAME=${OPTARG} ;;
p) PORT=${OPTARG} ;;
d) DEBUG=true
DEBUG_PORT=${OPTARG}
echo "debug enabled, port $DEBUG_PORT"
;;
j) if [[ ${accepted_java_versions[@]} =~ ${OPTARG} ]]; then
java_version=${OPTARG}
else
echo "Invalid java version" && echo "accepted version are: ${accepted_java_versions[@]}" && exit 1
fi
;;
h) Help && exit 0 ;;
:) # matched when an option that is expected to have an argument is passed without one
if [ ${OPTARG} = "d" ]; then
DEBUG=true
echo "debug enabled, port $DEBUG_PORT"
else
# matched when an option that is expected to have an argument is passed without one
echo "Option -${OPTARG} requires an argument."
exit 1
fi
;;
?) # match any invalid option that is passed
echo "Invalid option: -${OPTARG}."
exit 1
;;
esac
done
if [ $COMPILE = true ]; then
mvn clean package
else
echo "skipping mvn package"
fi
docker build -t $NAME --build-arg JAVA_VERSION=${java_version} .
if [ $DEBUG = false ]; then
docker run -p $PORT:8080 $NAME
else
docker run -p $PORT:8080 -p $DEBUG_PORT:5005 -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=*:5005,server=y,suspend=y" $NAME
fi

View File

@ -1,8 +0,0 @@
mvn clean package
NAME=idm
PORT=8080
DEBUG_PORT=5005
docker build -t $NAME .
docker run -p $PORT:8080 -p $DEBUG_PORT:5005 -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=*:5005,server=y,suspend=y" $NAME

View File

@ -20,6 +20,6 @@ location = pisa
factory = org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory
factory.endpoint = https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token
credentials.class = org.gcube.smartgears.security.SimpleCredentials
credentials.clientID = node-whn-test-uno-d-d4s.d4science.org
#credentials.clientID = alfredo-idm-service-dev
#credentials.clientID = node-whn-test-uno-d-d4s.d4science.org
credentials.clientID = alfredo-idm-service-dev
credentials.secret = 979bd3bc-5cc4-11ec-bf63-0242ac130002

View File

@ -8,10 +8,16 @@
A gcube service - smartgears 4
</description>
<servlet>
<servlet-name>org.gcube.service.idm.IdM</servlet-name>
<servlet-name>idm</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>org.gcube.service.idm.rest</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>org.gcube.service.idm.IdM</servlet-name>
<servlet-name>idm</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

170
pom.xml
View File

@ -1,24 +1,21 @@
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.gcube.idm</groupId>
<artifactId>idm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>Identity Manager Smargears</name>
<description>Identity Manager Smargears Service</description>
<packaging>war</packaging>
<parent>
<groupId>org.gcube.tools</groupId>
<artifactId>maven-parent</artifactId>
<version>1.2.0</version>
</parent>
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -28,8 +25,11 @@
<!-- OPTIONAL. for authorization-control-library -->
<aspectj-plugin.version>1.14.0</aspectj-plugin.version>
<!-- OPTIONAL. for enunciate -->
<!-- bind jackson version to avoid inconsistences with keycloak dependencies -->
<jackson.version>2.15.3</jackson.version>
<enunciate.version>2.14.0</enunciate.version>
</properties>
<scm>
@ -37,7 +37,8 @@
scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</connection>
<developerConnection>
scm:git:https://code-repo.d4science.org/gCubeSystem/${project.artifactId}.git</developerConnection>
<url>https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
<url>
https://code-repo.d4science.org/gCubeSystem/${project.artifactId}</url>
</scm>
<dependencyManagement>
@ -53,6 +54,80 @@
</dependencyManagement>
<dependencies>
<!--
Keycloak use a older version of jackson (2.12.3).
some jackson libraries are imported only by keyclock,
not by smartgears so it mixed different versions.
We explicity import its jackson dependency to ovverride the version
-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-base</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.2</version>
</dependency>
<!--
usermanagement-core depends on older httpcommon and gives this error on keycloak client:
java.lang.NoClassDefFoundError: org/apache/http/ssl/TrustStrategy
https://stackoverflow.com/questions/44750124/classnotfoundexception-on-org-apache-http-ssl-truststrategy
solution: bind version, or exclude them in usermanagement-core
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.13</version>
</dependency>
-->
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>21.1.2</version>
<exclusions>
<exclusion>
<groupId>org.jboss.spec.javax.ws.rs</groupId>
<artifactId>jboss-jaxrs-api_3.0_spec</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<!-- smartgears -->
<dependency>
<groupId>org.gcube.core</groupId>
@ -62,6 +137,18 @@
<groupId>org.gcube.common</groupId>
<artifactId>common-security</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>common-authorization</artifactId>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-utils</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.gcube.common</groupId>
<artifactId>authorization-control-library</artifactId>
@ -72,25 +159,18 @@
</dependency>
<!-- jersey -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-cdi2-se -->
<!--
https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-cdi2-se -->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-cdi2-se</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- add jackson as json provider -->
<dependency>
@ -129,15 +209,56 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>portal-service</artifactId>
<version>6.2.5</version>
<scope>compile</scope>
</dependency>
<!--
usermanagement-core depends on older httpcommon and gives this error on keycloak client:
java.lang.NoClassDefFoundError: org/apache/http/ssl/TrustStrategy
https://stackoverflow.com/questions/44750124/classnotfoundexception-on-org-apache-http-ssl-truststrategy
-->
<dependency>
<groupId>org.gcube.dvos</groupId>
<artifactId>usermanagement-core</artifactId>
<version>[2.0.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- OPTIONAL generate the war in a different folder, to mount deploy on docker
<!-- OPTIONAL generate the war in a different folder, that will be
mounted on docker
container -->
<!-- <plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
@ -145,9 +266,11 @@
<warName>identity-manager</warName>
<outputDirectory>tomcat/webapps</outputDirectory>
</configuration>
</plugin> -->
</plugin>
-->
<!-- OPTIONAL. authorization-control-library: add this plugin if you want to use gcube
<!-- OPTIONAL. authorization-control-library: add this plugin if you
want to use gcube
authorization control funzionalities -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
@ -240,5 +363,4 @@
</plugins>
</build>
</project>

View File

@ -0,0 +1,47 @@
package org.gcube.keycloack;
public class ErrorMessages {
protected static final String NOT_USER_TOKEN_CONTEXT_USED = "User's information can only be retrieved through a user token (not qualified)";
protected static final String CANNOT_RETRIEVE_SERVICE_ENDPOINT_INFORMATION = "Unable to retrieve such service endpoint information";
private static final String NO_RUNTIME_RESOURCE_TEMPLATE_NAME_CATEGORY = "There is no Runtime Resource having name %s and Category %s in this scope";
public static final String MISSING_TOKEN = "Missing token.";
public static final String MISSING_PARAMETERS = "Missing request parameters.";
public static final String INVALID_TOKEN = "Invalid token.";
public static final String TOKEN_GENERATION_APP_FAILED = "Token generation failed.";
public static final String NOT_APP_TOKEN = "Invalid token: not belonging to an application.";
public static final String NOT_APP_ID = "Invalid application id: it doesn't belong to an application.";
public static final String NO_APP_PROFILE_FOUND = "There is no application profile for this app id/scope.";
public static final String BAD_REQUEST = "Please check the parameter you passed, it seems a bad request";
public static final String ERROR_IN_API_RESULT = "The error is reported into the 'message' field of the returned object";
public static final String POST_OUTSIDE_VRE = "A post cannot be written into a context that is not a VRE";
public static final String DEPRECATED_METHOD = "This method is deprecated, must use version 2";
protected static final String no_runtime_category(String runtime, String category) {
return String.format(NO_RUNTIME_RESOURCE_TEMPLATE_NAME_CATEGORY, runtime, category);
}
// public static final String MISSING_TOKEN = "Missing token.";
// public static final String MISSING_PARAMETERS = "Missing request
// parameters.";
// public static final String INVALID_TOKEN = "Invalid token.";
// public static final String TOKEN_GENERATION_APP_FAILED = "Token generation
// failed.";
// public static final String NOT_APP_TOKEN = "Invalid token: not belonging to
// an application.";
// public static final String NOT_APP_ID = "Invalid application id: it doesn't
// belong to an application.";
// public static final String NO_APP_PROFILE_FOUND = "There is no application
// profile for this app id/scope.";
// public static final String BAD_REQUEST = "Please check the parameter you
// passed, it seems a bad request";
// public static final String ERROR_IN_API_RESULT = "The error is reported into
// the 'message' field of the returned object";
// public static final String POST_OUTSIDE_VRE = "A post cannot be written into
// a context that is not a VRE";
// public static final String DEPRECATED_METHOD = "This method is deprecated,
// must use version 2";
}

View File

@ -0,0 +1,24 @@
package org.gcube.keycloack;
import org.keycloak.admin.client.Keycloak;
public class KeycloackApiClient {
public Keycloak kclient;
public String realmName;
public String clientIdContext;
public String context;
public static String getClientIdContext(String context){
return context.replace("/", "%2F");
}
public KeycloackApiClient(Keycloak kclient, String realmName, String context) {
this.clientIdContext = getClientIdContext(context);
this.context = context;
this.kclient = kclient;
this.realmName = realmName;
//ClientsResource clients = kclient.realm(realmName).clients().get*
//clients.get(context);
}
}

View File

@ -0,0 +1,124 @@
package org.gcube.keycloack;
import java.io.InputStream;
import java.net.URL;
import java.util.AbstractMap.SimpleEntry;
import java.util.Map.Entry;
import java.util.Properties;
import jakarta.ws.rs.InternalServerErrorException;
import org.gcube.common.authorization.utils.secret.JWTSecret;
import org.gcube.common.keycloak.DefaultKeycloakClient;
import org.gcube.common.keycloak.KeycloakClientException;
import org.gcube.common.keycloak.KeycloakClientFactory;
import org.gcube.common.keycloak.model.TokenResponse;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.gcube.common.authorization.utils.secret.Secret;
/***
* from gcat implementation
*
*/
public class KeycloackClientGcatFactory {
private static final Logger logger = LoggerFactory.getLogger(KeycloackClientGcatFactory.class);
public static final String CATALOGUE_NAME = "IDM";
protected static final String CLIENT_ID_SECRET_FILENAME = "config.properties";
protected static final String CLIENT_ID_PROPERTY_NAME = "clientId";
public String context;
public String clientId;
public String clientSecret;
public DefaultKeycloakClient gcubeKeycloakClient;
// Reads the property file and extracts the keycloack configuration params
protected static Entry<String, String> getClientIdAndClientSecret(String context) {
try {
Properties properties = new Properties();
ClassLoader classLoader = KeycloackClientGcatFactory.class.getClassLoader();
URL url = classLoader.getResource(CLIENT_ID_SECRET_FILENAME);
logger.trace("Going to read {} at {}", CLIENT_ID_SECRET_FILENAME, url.toString());
InputStream input = classLoader.getResourceAsStream(CLIENT_ID_SECRET_FILENAME);
properties.load(input);
String clientId = "IDM";
if (properties.containsKey(CLIENT_ID_PROPERTY_NAME)) {
clientId = properties.getProperty(CLIENT_ID_PROPERTY_NAME);
}
int index = context.indexOf('/', 1);
String root = context.substring(0, index == -1 ? context.length() : index);
String clientSecret = properties.getProperty(root);
SimpleEntry<String, String> entry = new SimpleEntry<String, String>(clientId, clientSecret);
return entry;
} catch (Exception e) {
throw new InternalServerErrorException(
"Unable to retrieve Application Token for context "
/*+ SecretManagerProvider.instance.get().getContext() */,
e);
}
}
// TODO: VERIFICARE
public URL getRealmBaseURL() throws KeycloakClientException {
return this.gcubeKeycloakClient.getRealmBaseURL(this.context);
}
public URL getRealmBaseURL(String realm) throws KeycloakClientException {
return this.gcubeKeycloakClient.getRealmBaseURL(this.context, realm);
}
public URL getServerURL() {
try {
return this.getRealmBaseURL();
} catch (KeycloakClientException e) {
// That should be almost impossible
logger.warn("Cannot create base URL", e);
return null;
}
}
public String getClientid() {
return clientId;
}
// TODO: serve? implementare
public String getPassword() {
return null;
}
// TODO: VERIFICARE
public String getRealm() {
return this.context;
}
public KeycloackClientGcatFactory(String context) {
this.context = context;
Entry<String, String> params = getClientIdAndClientSecret(context);
this.clientId = params.getKey();
this.clientSecret = params.getKey();
this.gcubeKeycloakClient = new DefaultKeycloakClient();
}
private static TokenResponse getJWTAccessToken() throws Exception {
String context = SecretManagerProvider.get().getContext();
Entry<String,String> entry = getClientIdAndClientSecret(context);
TokenResponse tr = KeycloakClientFactory.newInstance().queryUMAToken(context, entry.getKey(), entry.getValue(), context, null);
return tr;
}
public static Secret getCatalogueSecret() throws Exception {
TokenResponse tr = getJWTAccessToken();
Secret secret = new JWTSecret(tr.getAccessToken());
return secret;
}
}

View File

@ -0,0 +1,172 @@
package org.gcube.keycloack;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.util.Iterator;
import java.util.List;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
// import org.keycloak.OAuth2Constants;
// import org.keycloak.admin.client.Keycloak;
// import org.keycloak.admin.client.KeycloakBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.QueryParam;
public class KeycloakClientFactory {
private static final Logger logger = LoggerFactory.getLogger(KeycloakClientFactory.class);
private final static String RUNTIME_RESOURCE_NAME = "IAM";
private final static String CATEGORY = "Service";
// the singleton obj
private static KeycloakClientFactory singleton = new KeycloakClientFactory();
// properties that it contains
private String keycloakURL;
private String realm;
private String clientid;
private String password;
/**
* Private constructor
*/
private KeycloakClientFactory() {
logger.info("Building KeycloakAPICredentials object");
lookupPropertiesFromIs();
logger.info("KeycloakAPICredentials object built");
}
/**
* Read the properties from the infrastructure
*/
private void lookupPropertiesFromIs() {
logger.info("Starting creating KeycloakAPICredentials");
// String ctx = SecretManagerProvider.instance.get().getContext();
// TODO: verificare che sia contesto corretto
ApplicationContext ctx = ContextProvider.get();
logger.info("Discovering liferay user's credentials in context "
+ ctx.container().configuration().infrastructure());
try {
List<ServiceEndpoint> resources = getConfigurationFromIS();
if (resources.size() == 0) {
logger.error("There is no Runtime Resource having name " + RUNTIME_RESOURCE_NAME + " and Category "
+ CATEGORY + " in this scope.");
throw new Exception("There is no Runtime Resource having name " + RUNTIME_RESOURCE_NAME
+ " and Category " + CATEGORY + " in this scope.");
} else {
for (ServiceEndpoint res : resources) {
Iterator<AccessPoint> accessPointIterator = res.profile().accessPoints().iterator();
while (accessPointIterator.hasNext()) {
ServiceEndpoint.AccessPoint accessPoint = (ServiceEndpoint.AccessPoint) accessPointIterator
.next();
if (accessPoint.name().equals("d4science")) {
keycloakURL = accessPoint.address();
realm = accessPoint.name();
clientid = accessPoint.username();
password = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
logger.info("Found accesspoint URL = " + keycloakURL);
}
}
}
}
} catch (Exception e) {
logger.error("Unable to retrieve such service endpoint information!", e);
return;
// }finally{
// if(oldContext != null)
// ScopeProvider.instance.set(oldContext);
}
logger.info("Bean built " + toString());
}
/**
* Retrieve endpoints information from IS for DB
*
* @return list of endpoints for ckan database
* @throws Exception
*/
private List<ServiceEndpoint> getConfigurationFromIS() throws Exception {
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '" + RUNTIME_RESOURCE_NAME + "'");
query.addCondition("$resource/Profile/Category/text() eq '" + CATEGORY + "'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}
public static KeycloakClientFactory getSingleton() {
if (singleton == null)
singleton = new KeycloakClientFactory();
return singleton;
}
public String getServerURL() {
return keycloakURL;
}
public String getClientid() {
return clientid;
}
public String getPassword() {
return password;
}
public String getRealm() {
return realm;
}
public KeycloackApiClient createtKeycloakInstance(String context) {
return defaultKeycloackInstance(context);
// // String clientIdContext = KeycloackUtils.getClientIdContext(context);
// String realm = this.getRealm();
// Keycloak keycloak = KeycloakBuilder.builder()
// .serverUrl(this.getServerURL())
// .realm(realm)
// .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
// .clientId(this.getClientid()) //
// .clientSecret(this.getPassword()).build();
// return
}
public KeycloackApiClient defaultKeycloackInstance(String context) {
String serverUrl = "https://accounts.dev.d4science.org/auth";
String realm = "d4science";
String clientId = "id.d4science.org";
String client_secret = "09c26f24-3c65-4039-9fa0-e5cc4f4032cd";
Keycloak kclient = KeycloakBuilder.builder()
.serverUrl(serverUrl)
.realm(realm)
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.clientId(clientId) //
.clientSecret(client_secret).build();
return new KeycloackApiClient(kclient, realm, context);
}
}

View File

@ -1,28 +0,0 @@
package org.gcube.service.idm;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import org.gcube.service.idm.test.services.AuthenticatedService;
import org.gcube.service.idm.test.services.ExcludeAuthorizationService;
import org.gcube.service.idm.test.services.HelloService;
/**
* @author Alfredo Oliviero (ISTI - CNR)
*/
@ApplicationPath("")
public class IdM extends Application {
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
// register resources and features
classes.add(HelloService.class);
classes.add(ExcludeAuthorizationService.class);
classes.add(AuthenticatedService.class);
return classes;
}
}

View File

@ -0,0 +1,85 @@
package org.gcube.service.idm.controller;
import java.util.List;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.keycloack.KeycloackApiClient;
import org.gcube.keycloack.KeycloakClientFactory;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
public class KKUserClient {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKUserClient.class);
// TODO: Move to KK CLIENTE
public static ClientResource getKKClientForContext() {
logger.info("Searching client for contex");
RealmResource realm = getKKRealmForContext();
String ctx = SecretManagerProvider.get().getContext();
KeycloackApiClient keycloackApiClient = KeycloakClientFactory.getSingleton()
.createtKeycloakInstance(ctx);
List<ClientRepresentation> clients = realm.clients().findByClientId(keycloackApiClient.clientIdContext);
String id = "";
for (ClientRepresentation client : clients) {
logger.info("found client =" + client.getClientId());
logger.info("found client id=" + client.getId());
id = client.getId();
}
ClientResource client = realm.clients().get(id);
return client;
}
// TODO: Move to KK CLIENTE
public static RealmResource getKKRealmForContext() {
logger.info("Searching client for contex");
String ctx = SecretManagerProvider.get().getContext();
KeycloackApiClient keycloackApiClient = KeycloakClientFactory.getSingleton()
.createtKeycloakInstance(ctx);
RealmResource realm = keycloackApiClient.kclient.realm(keycloackApiClient.realmName);
return realm;
}
public static List<UserRepresentation> getUserByEmail(String email) {
logger.info("Searching user by email: {}", email);
RealmResource realm = getKKRealmForContext();
List<UserRepresentation> users = realm.users()
.searchByEmail(email, true);
return users;
}
public static List<UserRepresentation> getUserByUsername(String username) {
logger.info("Searching user by username: {}", username);
RealmResource realm = getKKRealmForContext();
List<UserRepresentation> users = realm.users()
.search(username, true);
return users;
}
public static List<UserRepresentation> searchUsersByRole(String roleName, Integer firstResult, Integer maxResults) {
logger.info("Searching users by role: {}", roleName);
ClientResource client = getKKClientForContext();
List<UserRepresentation> users = client.roles().get(roleName)
.getUserMembers(firstResult, maxResults);
return users;
}
public static List<UserRepresentation> searchRealmUsers(Integer firstResult, Integer maxResults) {
RealmResource realm = getKKRealmForContext();
List<UserRepresentation> users = realm.users()
.list(firstResult, maxResults);
return users;
}
}

View File

@ -1,61 +0,0 @@
package org.gcube.service.idm.rest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.service.idm.IdMManager;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// import com.webcohesion.enunciate.metadata.rs.RequestHeader;
// import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
// import com.webcohesion.enunciate.metadata.rs.ResourceGroup;
// import com.webcohesion.enunciate.metadata.rs.ResourceLabel;
@ManagedBy(IdMManager.class)
@Path("/test")
// @ResourceGroup("test")
// @ResourceLabel("test")
// @RequestHeaders({
// @RequestHeader(name = "Authorization", description = "Bearer token, see <a href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>")
// })
public class TestRest {
private final Logger logger = LoggerFactory.getLogger(TestRest.class);
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
InnerMethodName.set("hello");
Secret secret = SecretManagerProvider.get();
String userId = secret.getOwner().getId();
String context = secret.getContext();
logger.info("caller id is {}", userId);
return String.format("Hello %s in context %s", userId, context);
}
@GET
@Path("/prova")
@Produces(MediaType.APPLICATION_JSON)
public String prova() {
logger.info("prova");
return "{'aaa':bbb'}";
}
@GET
@Path("show_context")
@Produces(MediaType.APPLICATION_JSON)
public String show_context() {
Secret smp = SecretManagerProvider.get();
String ctx = smp.getContext();
return ctx;
}
}

View File

@ -1,139 +0,0 @@
package org.gcube.service.idm.rest;
import org.gcube.common.authorization.library.policies.Users;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.rest.ResponseBean;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
// @Path("2/users")
// @ResourceGroup("Users APIs")
// @ResourceLabel("Greetings APIs")
// @RequestHeaders({
// @RequestHeader(name = "Authorization", description = "Bearer token, see <a
// href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>")
// })
public class UsersRest {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Users.class);
// @GET
// @Path("/get-usernames-by-role")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public Response getUsernamesByRole(
// @QueryParam("role-name") String roleName) {
// Status status = Status.OK;
// ResponseBean responseBean = new ResponseBean();
// List<String> usernames = new ArrayList<String>();
// try {
// String ctx = SecretManagerProvider.get().getContext();
// KeycloakApiClient keycloackApiClient = KeycloakAPIFactory.getSingleton().createtKeycloakInstance(ctx);
// List<UserRepresentation> users = null; // searchByRole(keycloackApiClient, roleName);
// if (users != null) {
// for (UserRepresentation user : users) {
// usernames.add(user.getUsername());
// }
// }
// responseBean.setResult(usernames);
// responseBean.setSuccess(true);
// } catch (Exception e) {
// logger.error("Unable to retrieve user with the requested role", e);
// responseBean.setMessage(e.getMessage());
// status = Status.INTERNAL_SERVER_ERROR;
// }
// return Response.status(status).entity(responseBean).build();
// }
// private static List<UserRepresentation> searchByRole(KeycloackApiClient keycloackApiClient, String roleName) {
// logger.info("Searching by role: {}", roleName);
// List<ClientRepresentation> clients = keycloackApiClient.kclient.realm(keycloackApiClient.realmName)
// .clients().findByClientId(keycloackApiClient.clientIdContext);
// String id = "";
// for (ClientRepresentation client : clients) {
// logger.info("found client =" + client.getClientId());
// logger.info("found client id=" + client.getId());
// id = client.getId();
// }
// List<UserRepresentation> users = keycloackApiClient.kclient.realm(keycloackApiClient.realmName)
// .clients()
// .get(id).roles().get(roleName)
// .getUserMembers(0, 100000);
// return users;
// }
// @GET
// @Path("/{get-profile}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getCurrentProfile() {
// // SMARTGEARS Specializza il tracciamento della chiamata su Accounting
// InnerMethodName.instance.set("getCurrentProfile");
// Owner owner = SecretManagerProvider.get().getOwner();
// ApplicationContext appContext = ContextProvider.get();
// SimpleCredentials credentials = ((DefaultAuthorizationProvider) appContext.container().authorizationProvider())
// .getCredentials();
// String ctx = SecretManagerProvider.get().getContext();
// KeycloackApiClient keycloackApiClient = KeycloakAPIFactory.getSingleton().createtKeycloakInstance(ctx);
// return null;
// }
// @GET
// @Path("/{get-email}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getCurrentEmail() {
// throw new NotImplementedYetException();
// }
// @GET
// @Path("/{get-fullname}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getCurrentFullname() {
// throw new NotImplementedYetException();
// }
// @GET
// @Path("/{get-all-usernames}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getAllUsernames() {
// throw new NotImplementedYetException();
// }
// @GET
// @Path("/{get-all-fullnames-and-usernames}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getAllUsernamesFullnames() {
// throw new NotImplementedYetException();
// }
// @GET
// @Path("/{user-exists}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public boolean checkUserExists() {
// throw new NotImplementedYetException();
// }
// @GET
// @Path("/{get-oauth-profile}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public boolean getCurrentOAuthProfile() {
// throw new NotImplementedYetException();
// }
}

View File

@ -0,0 +1,336 @@
package org.gcube.service.idm.rest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import org.gcube.common.authorization.library.policies.Users;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.keycloack.ErrorMessages;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.KKUserClient;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.validation.ValidationException;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.core.MediaType;
@ManagedBy(IdMManager.class)
@Path("users")
// @ResourceGroup("Users APIs")
// @ResourceLabel("Greetings APIs")
// @RequestHeaders({
// @RequestHeader(name = "Authorization", description = "Bearer token, see <a
// href=\"https://dev.d4science.org/how-to-access-resources\">https://dev.d4science.org/how-to-access-resources</a>")
// })
public class UsersSocialAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(Users.class);
private static final String NOT_USER_TOKEN_CONTEXT_USED = "User's information can only be retrieved through a user token (not qualified)";
private static final List<String> GLOBAL_ROLES_ALLOWED_BY_LOCAL_CALL_METHOD = Arrays.asList("DataMiner-Manager",
"Quota-Manager");
@GET
@Path("/get-usernames-by-role")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getUsernamesByRole(
@QueryParam("role-name") String roleName,
@QueryParam("firstResult") @DefaultValue("0") @Min(value = 0, message = "from cannot be negative") int firstResult,
@QueryParam("maxResults") @DefaultValue("100000") @Min(value = 0, message = "quantity cannot be negative") int maxResults) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
List<String> usernames = new ArrayList<String>();
try {
List<UserRepresentation> users = KKUserClient.searchUsersByRole(roleName, firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
}
}
responseBean.setResult(usernames);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
return Response.serverError().build();
} catch (Exception e) {
logger.error("Unable to retrieve users with the requested role", e);
// responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
@GET
@Path("/get-all-fullnames-and-usernames")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getAllUsernamesFullnames(
@QueryParam("firstResult") @DefaultValue("0") @Min(value = 0, message = "from cannot be negative") int firstResult,
@QueryParam("maxResults") @DefaultValue("100000") @Min(value = 0, message = "quantity cannot be negative") int maxResults) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
Map<String, String> usernamesAndFullnames = new HashMap<String, String>();
try {
List<UserRepresentation> users = KKUserClient.searchRealmUsers(firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernamesAndFullnames.put(user.getUsername(), user.getEmail());
}
}
responseBean.setResult(usernamesAndFullnames);
responseBean.setSuccess(true);
} catch (Exception e) {
logger.error("Unable to retrieve users", e);
// responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
/**
* Read a user's custom attribute. The user is the one owning the token
*
* @param attributeKey The key of the attribute to be read
* @return the user's custom attribute
* @throws ValidationException
*/
@GET
@Path("get-custom-attribute/")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "Successful read of the attribute, reported in the 'result' field of the returned object"),
@ResponseCode(code = 404, condition = "Such an attribute doesn't exist"),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response readCustomAttr(
@QueryParam("attribute") @NotNull(message = "attribute name is missing") String attributeKey)
throws ValidationException {
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
Secret secret = SecretManagerProvider.get();
// Owner owner = secret.getOwner();
String userId = secret.getOwner().getId();
// String context = secret.getContext();
// TODO: aggiornare implementazione
// if (!TokensUtils.isUserTokenDefault(caller)) {
// status = Status.FORBIDDEN;
// responseBean.setMessage(NOT_USER_TOKEN_CONTEXT_USED);
// logger.warn("Trying to access users method via a token different than USER is
// not allowed");
// return Response.status(status).entity(responseBean).build();
// }
UserManager lr_userManager = null; //UserManagerWSBuilder.getInstance().getUserManager();
try {
GCubeUser user = lr_userManager.getUserByUsername(userId);
String toReturn = (String) lr_userManager.readCustomAttr(user.getUserId(), attributeKey);
responseBean.setSuccess(true);
responseBean.setResult(toReturn);
} catch (Exception e) {
logger.error("Unable to retrieve attribute for user.", e);
responseBean.setMessage(e.toString());
responseBean.setSuccess(false);
status = Status.NOT_FOUND;
}
return Response.status(status).entity(responseBean).build();
}
/**
* Get the profile associated to the token
*
* @responseExample application/json { "success" : true, "message" : null,
* "result" : { "user_id" : 23769487, "username" :
* "john.smith", "email" : "********", "first_name" : "John",
* "middle_name" : "", "last_name" : "Smith", "fullname" :
* "John Smith", "registration_date" : 1475151491415,
* "user_avatar_url" : "https://******D", "male" : true,
* "job_title" : "", "location_industry" : "no",
* "custom_attrs_map" : null, "email_addresses" : [ ],
* "screen_name" : "john.smith", "user_avatar_id" :
* "https://****sY%3D" } }
* @return the user's profile. The user is the one owning the token
*/
@GET
@Path("get-profile")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "The user's profile is reported in the 'result' field of the returned object"),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getUserProfile() {
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
Secret secret = SecretManagerProvider.get();
// Owner owner = secret.getOwner();
String userId = secret.getOwner().getId();
// String context = secret.getContext();
// TODO: aggiornare implementazione
// if (!TokensUtils.isUserTokenDefault(caller)) {
// status = Status.FORBIDDEN;
// responseBean.setMessage(NOT_USER_TOKEN_CONTEXT_USED);
// logger.warn("Trying to access users method via a token different than USER is
// not allowed");
// return Response.status(status).entity(responseBean).build();
// }
UserManager lr_userManager = null; // UserManagerWSBuilder.getInstance().getUserManager();
try {
GCubeUser userprofiile = lr_userManager.getUserByUsername(userId);
responseBean.setResult(userprofiile);
responseBean.setSuccess(true);
} catch (Exception e) {
logger.error("Unable to retrieve user's profile", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
@GET
@Path("/get-email")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getCurrentEmail() {
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
try {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
String email = owner.getEmail();
responseBean.setResult(email);
responseBean.setSuccess(true);
} catch (Exception e) {
logger.error("Unable to retrieve user's email", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
// @GET
// @Path("/get-fullname")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public String getCurrentFullname() {
// throw new NotImplementedYetException();
// }
@GET
@Path("/get-all-usernames")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getUsernamesByRole(
@QueryParam("firstResult") @DefaultValue("0") @Min(value = 0, message = "from cannot be negative") int firstResult,
@QueryParam("maxResults") @DefaultValue("100000") @Min(value = 0, message = "quantity cannot be negative") int maxResults) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
List<String> usernames = new ArrayList<String>();
try {
List<UserRepresentation> users = KKUserClient.searchRealmUsers(firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
}
}
responseBean.setResult(usernames);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
return Response.serverError().build();
} catch (Exception e) {
logger.error("Unable to retrieve users with the requested role", e);
// responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
@GET
@Path("/user-exists")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response checkUserExists(@QueryParam("username") String username) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
List<UserRepresentation> users = KKUserClient.getUserByUsername(username);
boolean user_exists = users != null && users.size() > 0;
responseBean.setResult(user_exists);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
return Response.serverError().build();
} catch (Exception e) {
logger.error("Unable to check if user exists with username " + username, e);
// responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
// @GET
// @Path("/get-oauth-profile")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public boolean getCurrentOAuthProfile() {
// throw new NotImplementedYetException();
// }
}

View File

@ -1,28 +1,23 @@
package org.gcube.service.idm.rest.test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.gcube.common.authorization.control.annotations.AuthorizationControl;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.service.idm.rest.TestRest;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Lucio Le (ISTI - CNR)
* @author Lucio Lelii (ISTI - CNR)
* @author Alfredo Oliviero (ISTI - CNR)
*/
@Path("auth")
public class AuthenticatedService {
private final Logger logger = LoggerFactory.getLogger(AuthenticatedService.class);
private static final String ALLOWED_ROLE = "myRole";
private static final String ALLOWED_ROLE_ORG = "OrganizationMember";
private static final String ALLOWED_ROLE_MEMBER = "Member";

View File

@ -1,7 +1,7 @@
package org.gcube.service.idm.test.services;
package org.gcube.service.idm.rest.test;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -1,14 +1,13 @@
package org.gcube.service.idm.rest.test;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
@ -17,7 +16,6 @@ import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.context.container.ContainerContext;
import org.gcube.smartgears.utils.InnerMethodName;
import org.slf4j.Logger;
@ -69,12 +67,7 @@ public class HelloService {
Owner owner = secret.getOwner();
data.put("owner", owner);
logger.info("details for {} - {} {} - {}", owner.getId(), owner.getFirstName(), owner.getLastName(), owner.getEmail());
ApplicationContext contextProvider = ContextProvider.get();
ContainerContext container = contextProvider.container();
//ContainerContext container = ContextProvider.get().container();
ContainerContext container = ContextProvider.get().container();
data.put("container", container);
ObjectMapper objectMapper = ContextSerializator.getSerializer();

View File

@ -0,0 +1,142 @@
package org.gcube.service.idm.rest.test;
import java.util.ArrayList;
import java.util.List;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.smartgears.annotations.ManagedBy;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Response;
@ManagedBy(IdMManager.class)
@Path("")
public class KeycloakTestService {
private final String CLIENT_SECRET = "NOT_COMMITTED";
private final static Logger logger = LoggerFactory.getLogger(KeycloakTestService.class);
public static String getClientIdContext(String context) {
return context.replace("/", "%2F");
}
@GET
@Path("keycloak")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response testKeycloak(
@QueryParam("serverUrl") @DefaultValue("https://accounts.dev.d4science.org/auth") String serverUrl,
@QueryParam("realm") @DefaultValue("d4science") String realm,
@QueryParam("role-name") @DefaultValue("Member") String roleName,
@QueryParam("client_id") @DefaultValue("id.d4science.org") String clientId,
@QueryParam("client_secret") @DefaultValue(CLIENT_SECRET) String client_secret
) {
String client_contenxt = "/gcube";
List<String> usernames = new ArrayList<String>();
try {
Keycloak kclient = KeycloakBuilder.builder()
.serverUrl(serverUrl)
.realm(realm)
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.clientId(clientId) //
.clientSecret(client_secret).build();
List<UserRepresentation> users = searchByRole(kclient, realm, client_contenxt, roleName);
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
}
}
// responseBean.setResult(usernames);
// responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(usernames);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
return Response.serverError().build();
} catch (Exception e) {
e.printStackTrace();
return Response.serverError().build();
}
// return Response.status(status).entity(responseBean).build();
}
private static List<UserRepresentation> searchByRole(Keycloak kclient, String krealm, String clientIdContext,
String roleName) {
clientIdContext = getClientIdContext(clientIdContext);
logger.info("Searching by role: {}", roleName);
RealmResource realm_resource = kclient.realm(krealm);
logger.info("{} realm_resource: {}", krealm, realm_resource);
ClientsResource clients_resource = realm_resource.clients();
logger.info("clients_resource {}", clients_resource);
for (ClientRepresentation c : clients_resource.findAll()) {
logger.info("listing all clients, found {} - {}", c.getClientId(), c.getId());
}
List<ClientRepresentation> clients_repr = clients_resource.findByClientId(clientIdContext);
logger.info("{} clients_repr: {}", clientIdContext, clients_repr);
String client_id = "";
for (ClientRepresentation c_repr : clients_repr) {
logger.info("searching {}, found client {} - {}", clientIdContext, c_repr.getClientId(), c_repr.getId());
client_id = c_repr.getId();
}
ClientResource client_resource = clients_resource.get(client_id);
logger.info("client_resource {}", client_resource);
RolesResource roles_resource = client_resource.roles();
for (RoleRepresentation r : roles_resource.list()) {
logger.info("found role {}", r);
}
logger.info("roles_resource {}", roles_resource);
RoleResource role_resource = roles_resource.get(roleName);
logger.info("{} role_resource: {}", roleName, roles_resource);
List<UserRepresentation> users_repr = role_resource.getUserMembers(0, 100000);
for (UserRepresentation u : users_repr) {
logger.info("found user {}", u);
}
return users_repr;
}
}

View File

@ -0,0 +1,80 @@
package org.gcube.service.idm.utils;
import org.gcube.common.authorization.library.ClientType;
import org.gcube.common.authorization.library.utils.Caller;
import org.slf4j.LoggerFactory;
/**
* Tokens utils methods
*/
public class TokensUtils {
// a user context token (not qualified) has as qualifier the word "TOKEN"
private static final String DEFAULT_QUALIFIER_USER_TOKEN = "TOKEN";
// Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TokensUtils.class);
/**
* Check if it is a service token
* @return a boolean value
*/
public static boolean isServiceToken(Caller caller){
return caller.getClient().getType().equals(ClientType.SERVICE);
}
/**
* Check if it is an application token
* @return a boolean value
*/
public static boolean isApplicationToken(Caller caller){
String username = caller.getClient().getId();
if (username.startsWith("service-account-")) {
return true;
}
return caller.getClient().getType().equals(ClientType.EXTERNALSERVICE);
}
/**
* Check if it is a container token
* @return a boolean value
*/
public static boolean isContainerToken(Caller caller){
return caller.getClient().getType().equals(ClientType.CONTAINER);
}
/**
* Check if it is a user token
* @return a boolean value
*/
public static boolean isUserToken(Caller caller) {
logger.debug("\n ****** \n isUserToken: caller.getClient().getType().equals(ClientType.USER) => " + caller.getClient().getType().equals(ClientType.USER));
String username = caller.getClient().getId();
if (username.startsWith("service-account-")) {
return false;
}
return caller.getClient().getType().equals(ClientType.USER);
}
/**
* Check if it is a user token (not qualified)
* @return a boolean value
*/
public static boolean isUserTokenDefault(Caller caller){
return isUserToken(caller);
}
/**
* Check if it is a user token (qualified)
* @return a boolean value
*/
public static boolean isUserTokenQualified(Caller caller){
return caller.getClient().getType().equals(ClientType.USER) && !caller.getTokenQualifier().equals(DEFAULT_QUALIFIER_USER_TOKEN);
}
}

View File

@ -5,7 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import jakarta.ws.rs.HttpMethod;
/**
* @author Luca Frosini (ISTI - CNR)

View File

@ -5,7 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.HttpMethod;
import jakarta.ws.rs.HttpMethod;
/**
* @author Luca Frosini (ISTI - CNR)

View File

@ -6,8 +6,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;