implemented Users and Roles Rest APIs

This commit is contained in:
Alfredo Oliviero 2024-03-29 18:14:50 +01:00
parent bc534cc6cb
commit 921bcd45cf
25 changed files with 2310 additions and 14395 deletions

View File

@ -4,7 +4,7 @@ FROM d4science/smartgears-distribution:4.0.0-SNAPSHOT-java$JAVA_VERSION-tomcat10
COPY ./docker/logback.xml /etc/
COPY ./docker/container.ini /etc/
COPY ./docker/devsec.gcubekey /tomcat/lib
COPY ./docker/*.gcubekey /tomcat/lib
COPY ./target/idm.war /tomcat/webapps/
EXPOSE 8080

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
{
"id": "e36a9994-fbaf-4bc1-b1db-bed90eeb8066",
"name": "/gcube/devNext",
"values": [
{
"key": "realm",
"value": "d4science",
"type": "default",
"enabled": true
},
{
"key": "username",
"value": "alfredo.oliviero",
"type": "default",
"enabled": true
},
{
"key": "scope_context",
"value": "/gcube/devNext",
"type": "default",
"enabled": true
},
{
"key": "key_password",
"value": "password_alfredo.oliviero",
"type": "default",
"enabled": false
},
{
"key": "proxy_disabled",
"value": "false",
"type": "default",
"enabled": true
}
],
"_postman_variable_scope": "environment",
"_postman_exported_at": "2024-02-12T16:38:58.342Z",
"_postman_exported_using": "Postman/10.23.0"
}

View File

@ -1,117 +0,0 @@
{
"id": "f1860155-0d84-4c0c-917b-2f8f015b2752",
"name": "/gcube/devsec/devVRE",
"values": [
{
"key": "realm",
"value": "d4science",
"type": "any",
"enabled": true
},
{
"key": "username",
"value": "alfredo.oliviero",
"type": "default",
"enabled": true
},
{
"key": "service_client_id",
"value": "id.d4science.org",
"type": "default",
"enabled": true
},
{
"key": "service_client_secret",
"value": "09c26f24-3c65-4039-9fa0-e5cc4f4032cd",
"type": "secret",
"enabled": true
},
{
"key": "proxy_disabled",
"value": "false",
"type": "default",
"enabled": true
},
{
"key": "scope_context",
"value": "/gcube/devsec/devVRE",
"type": "default",
"enabled": true
},
{
"key": "key_password",
"value": "password_alfredo.oliviero",
"type": "default",
"enabled": false
},
{
"key": "current_context",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "current_url-encoded-context",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "current_iam-url",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "current_client-id",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "keycloak_url",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "token",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "refresh_token",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "id_token",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "clientId",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "current_password",
"value": "",
"type": "any",
"enabled": true
},
{
"key": "current_username",
"value": "",
"type": "any",
"enabled": true
}
],
"_postman_variable_scope": "environment",
"_postman_exported_at": "2024-02-12T16:38:53.606Z",
"_postman_exported_using": "Postman/10.23.0"
}

View File

@ -1,45 +0,0 @@
{
"id": "07ce7746-e9f4-443a-a651-81960a029729",
"name": "/gcube",
"values": [
{
"key": "realm",
"value": "d4science",
"type": "default",
"enabled": true
},
{
"key": "username",
"value": "alfredo.oliviero",
"type": "default",
"enabled": true
},
{
"key": "proxy_disabled",
"value": "false",
"type": "default",
"enabled": true
},
{
"key": "scope_context",
"value": "/gcube",
"type": "default",
"enabled": true
},
{
"key": "key_password",
"value": "password_alfredo.oliviero",
"type": "default",
"enabled": false
},
{
"key": "keycloak_url",
"value": "",
"type": "any",
"enabled": true
}
],
"_postman_variable_scope": "environment",
"_postman_exported_at": "2024-02-12T16:39:02.914Z",
"_postman_exported_using": "Postman/10.23.0"
}

View File

@ -1,378 +0,0 @@
{
"info": {
"_postman_id": "89ef223a-9bf5-4000-adf9-848f1570b560",
"name": "KeycloakRest IDM API",
"description": "Keycloak Admin Rest API v10 (https://www.keycloak.org/docs-api/10.0/rest-api/index.html)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "32856827"
},
"item": [
{
"name": "[SAT] Get Realms",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var clients = JSON.parse(responseBody);",
"",
"console.log(\" clients: \", clients);",
"var scope_encoded_context = pm.environment.get(\"current_url-encoded-context\");",
"",
"var scope_context = pm.environment.get(\"current_context\");",
"",
"console.log(\"scope_encoded_context: \", scope_encoded_context);",
"console.log(\"scope_context: \", scope_context);",
"",
"//var client = clients.find( (c) => c.name == scope_context);",
"",
"var client = clients.find( (c) => c.clientId == scope_encoded_context);",
"console.log(\">> current client: \", client);",
"",
"if (client) {",
" pm.environment.set(\"clientId\", client.id)",
"}",
"",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms"
]
}
},
"response": []
},
{
"name": "[SAT] Get Clients",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var clients = JSON.parse(responseBody);",
"",
"console.log(\" clients: \", clients);",
"var scope_encoded_context = pm.environment.get(\"current_url-encoded-context\");",
"",
"var scope_context = pm.environment.get(\"current_context\");",
"",
"console.log(\"scope_encoded_context: \", scope_encoded_context);",
"console.log(\"scope_context: \", scope_context);",
"",
"//var client = clients.find( (c) => c.name == scope_context);",
"",
"var client = clients.find( (c) => c.clientId == scope_encoded_context);",
"console.log(\">> current client: \", client);",
"",
"if (client) {",
" pm.environment.set(\"clientId\", client.id)",
"}",
"",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/clients",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"clients"
]
},
"description": "Get clients belonging to the realm Returns a list of clients belonging to the realm"
},
"response": []
},
{
"name": "[SAT] Get client role users by role name",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/clients/{{clientId}}/roles/Catalogue-Editor/users",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"clients",
"{{clientId}}",
"roles",
"Catalogue-Editor",
"users"
]
},
"description": "Get all roles for the realm or client"
},
"response": []
},
{
"name": "[SAT] Get all roles for the realm or client",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{token}}",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/clients/{{clientId}}/roles",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"clients",
"{{clientId}}",
"roles"
]
}
},
"response": []
},
{
"name": "[SAT] Get users for realm",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/users",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"users"
],
"query": [
{
"key": "briefRepresentation",
"value": "",
"disabled": true
},
{
"key": "email",
"value": "",
"disabled": true
},
{
"key": "first",
"value": "",
"disabled": true
},
{
"key": "firstName",
"value": "",
"disabled": true
},
{
"key": "lastName",
"value": "",
"disabled": true
},
{
"key": "max",
"value": "",
"disabled": true
},
{
"key": "search",
"value": "",
"disabled": true
},
{
"key": "username",
"value": "",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "[SAT] Search users by email in realm",
"request": {
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/users?email=alfredo.oliviero@isti.cnr.it",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"users"
],
"query": [
{
"key": "briefRepresentation",
"value": "",
"disabled": true
},
{
"key": "first",
"value": "",
"disabled": true
},
{
"key": "firstName",
"value": "",
"disabled": true
},
{
"key": "lastName",
"value": "",
"disabled": true
},
{
"key": "max",
"value": "",
"disabled": true
},
{
"key": "search",
"value": "",
"disabled": true
},
{
"key": "username",
"value": "",
"disabled": true
},
{
"key": "email",
"value": "alfredo.oliviero@isti.cnr.it"
}
]
}
},
"response": []
}
],
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{token}}",
"type": "string"
}
]
},
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "keycloak_url",
"value": "https://accounts.dev.d4science.org"
},
{
"key": "realm",
"value": "d4science"
}
]
}

View File

@ -1,445 +0,0 @@
{
"info": {
"_postman_id": "a19897ba-741b-4011-9618-862fec1b2a84",
"name": "KeycloakRestAPI -Auth Token Requests",
"description": "retrieves and sets the auth token\n\nbefore executing\n\n- update environment.username to current username\n- add in environment or in global the variable \"password_USERNAME\" , type secret, with the reletated password\n- add an empty variable \"current_password\", type secret, in Global Config to hide the current_password\n \n\nto check execution, open the Postman Console (View => Show Postman Console)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "32856827"
},
"item": [
{
"name": "clear context",
"event": [
{
"listen": "prerequest",
"script": {
"exec": [
"console.log(\"executing clear script\");",
"",
" pm.environment.unset('current_username');",
" pm.environment.unset('current_password');",
" pm.environment.unset('current_context');",
" pm.environment.unset('current_url-encoded-context');",
" pm.environment.unset('current_iam-url');",
" pm.environment.unset('current_client-id');",
" pm.environment.unset('current_uma-token');",
" pm.environment.unset('current_access-token');",
"",
"",
" pm.environment.unset('token');",
" pm.environment.unset('refresh_token');",
" pm.environment.unset('id_token');",
" pm.environment.unset('keycloak_url');",
"",
" pm.environment.unset('clientId');"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "/",
"path": [
""
]
}
},
"response": []
},
{
"name": "[SAT] Obtain accsess token from a service account",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = JSON.parse(responseBody);",
"postman.setEnvironmentVariable(\"token\", jsonData.access_token);",
"postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);",
"postman.setEnvironmentVariable(\"id_token\", jsonData.id_token);",
"",
"",
"postman.setNextRequest('[SAT][UAT] Set Current Client ID');",
""
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/x-www-form-urlencoded",
"type": "text"
}
],
"body": {
"mode": "urlencoded",
"urlencoded": [
{
"key": "client_id",
"value": "{{service_client_id}}",
"type": "text"
},
{
"key": "client_secret",
"value": "{{service_client_secret}}",
"type": "text"
},
{
"key": "grant_type",
"value": "client_credentials",
"type": "text"
}
]
},
"url": {
"raw": "{{keycloak_url}}/realms/{{realm}}/protocol/openid-connect/token",
"host": [
"{{keycloak_url}}"
],
"path": [
"realms",
"{{realm}}",
"protocol",
"openid-connect",
"token"
]
},
"description": "Obtain SAT (service account token)"
},
"response": []
},
{
"name": "[UAT] Obtain access token for a user",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = JSON.parse(responseBody);",
"postman.setEnvironmentVariable(\"token\", jsonData.access_token);",
"postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);",
"postman.setEnvironmentVariable(\"id_token\", jsonData.id_token);",
"",
"postman.setEnvironmentVariable(\"current_access-token\", jsonData.access_token);",
""
],
"type": "text/javascript"
}
},
{
"listen": "prerequest",
"script": {
"exec": [
"function set_user_pass(){",
" var username = pm.variables.get('username');",
"",
" console.log('current username', pm.variables.get('username'));",
"",
" var pwd_key = 'password_' + username;",
" if (pm.variables.has('key_password')) {",
" pwd_key = pm.variables.get('key_password')",
" }",
"",
" if (pm.variables.has(pwd_key)) {",
" password = pm.variables.get(pwd_key);",
" } else {",
" throw new Error(\"missing password for username \" + username + \". Set a global password (type secret) with key \" + pwd_key);",
" }",
" pm.environment.set('current_password', password );",
" console.log('password ****** from', pwd_key );",
"",
" pm.environment.set('current_username', username);",
" pm.environment.set('current_password', password);",
"}",
"",
"set_user_pass();"
],
"type": "text/javascript"
}
}
],
"request": {
"auth": {
"type": "noauth"
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/x-www-form-urlencoded",
"type": "text"
}
],
"body": {
"mode": "urlencoded",
"urlencoded": [
{
"key": "client_id",
"value": "admin-cli",
"type": "text"
},
{
"key": "username",
"value": "{{current_username}}",
"type": "text"
},
{
"key": "password",
"value": "{{current_password}}",
"type": "text"
},
{
"key": "grant_type",
"value": "password",
"type": "text"
}
]
},
"url": {
"raw": "{{keycloak_url}}/realms/{{realm}}/protocol/openid-connect/token",
"host": [
"{{keycloak_url}}"
],
"path": [
"realms",
"{{realm}}",
"protocol",
"openid-connect",
"token"
]
},
"description": "Obtain UAT = user access token from a user in realm"
},
"response": []
},
{
"name": "[SAT][UAT] Set Current Client ID",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var clients = JSON.parse(responseBody);",
"",
"console.log(\" clients: \", clients);",
"var scope_encoded_context = pm.environment.get(\"current_url-encoded-context\");",
"",
"var scope_context = pm.environment.get(\"current_context\");",
"",
"console.log(\"scope_encoded_context: \", scope_encoded_context);",
"console.log(\"scope_context: \", scope_context);",
"",
"//var client = clients.find( (c) => c.name == scope_context);",
"",
"var client = clients.find( (c) => c.clientId == scope_encoded_context);",
"console.log(\">> current client: \", client);",
"",
"if (client) {",
" pm.environment.set(\"clientId\", client.id)",
"}",
"",
""
],
"type": "text/javascript"
}
}
],
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{token}}",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json",
"disabled": true
}
],
"url": {
"raw": "{{keycloak_url}}/admin/realms/{{realm}}/clients",
"host": [
"{{keycloak_url}}"
],
"path": [
"admin",
"realms",
"{{realm}}",
"clients"
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
"console.log(\"executing pre-request script\");",
"",
"",
"var scope_context = pm.environment.get('scope_context');",
"",
"if (!scope_context) {",
" throw new Error(\"scope_context not defined\" );",
"}",
"",
"console.log('current context', scope_context);",
"pm.environment.set('current_context', scope_context);",
"",
"var urlEncodedContext = encodeURIComponent(scope_context);",
"pm.environment.set('current_url-encoded-context', urlEncodedContext);",
"",
"",
"var iamURL;",
"var clientID;",
"var prefix;",
"",
"if(scope_context.startsWith('/gcube')){",
" prefix = \"gcube_\";",
"} else if(scope_context.startsWith('/pred4s')) {",
" prefix = \"pred4s_\";",
"} else if(scope_context.startsWith('/d4science.research-infrastructures')) { ",
" prefix = \"d4science_\";",
"} else {",
" throw new Error(\"missing context parameters \" + context);",
"}",
"",
"var proxy_disabled = pm.variables.has(proxy_disabled) && pm.variables.get('proxy_disabled') == \"true\";",
"",
"var key_iamURL = prefix + \"iam_url\";",
"var key_client = prefix + \"client-id\";",
"",
"if (proxy_disabled) {",
" console.log(\"proxy disabled, bypassing proxy\")",
" key_iamURL += \"_noproxy\";",
"}",
"",
"console.log(\"key_iamURL\", key_iamURL);",
"console.log(\"key_client\", key_client);",
"",
"iamURL = pm.variables.get(key_iamURL) ;",
"clientID = pm.variables.get(key_client);",
"",
"console.log(\"current iamURL\", iamURL);",
"console.log(\"current clientID\", clientID);",
"",
"pm.environment.set('current_iam-url', iamURL);",
"pm.environment.set('current_client-id', clientID);",
"",
"pm.environment.set('keycloak_url', iamURL + '/auth') ;",
"",
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "password_mister.blonde",
"value": "oxv:3662"
},
{
"key": "password_mister.brown",
"value": "pqm-6054"
},
{
"key": "password_mister.pink",
"value": "pum*7692"
},
{
"key": "password_mister.white",
"value": "pav_0026"
},
{
"key": "password_mister.blue",
"value": "mbsl-2367"
},
{
"key": "password_mister.orange",
"value": "mrsn-3188"
},
{
"key": "iam-url",
"value": ""
},
{
"key": "client-id-user",
"value": ""
},
{
"key": "gcube_client-id",
"value": "next.d4science.org"
},
{
"key": "gcube_iam_url_noproxy",
"value": "https://url.gcube.d4science.org",
"type": "string"
},
{
"key": "gcube_iam_url",
"value": "https://accounts.dev.d4science.org",
"type": "string"
},
{
"key": "pred4s_iam_url",
"value": "https://url.pred4s.d4science.org",
"type": "string"
},
{
"key": "pred4s_client-id",
"value": "pre.d4science.org",
"type": "string"
},
{
"key": "d4science_iam_url",
"value": "https://url.d4science.org",
"type": "string"
},
{
"key": "c_client",
"value": "services.d4science.org",
"type": "string"
},
{
"key": "d4science_iam_url_noproxy",
"value": "https://accounts.d4science.org",
"type": "string"
},
{
"key": "pred4s_iam_url_noproxy",
"value": "https://accounts.pre.d4science.org",
"type": "string"
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -1,162 +0,0 @@
package org.gcube.keycloack;
import java.util.List;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.is.client.InfrastrctureServiceClient;
import org.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
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.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException;
public class KkClientFactory {
private static final Logger logger = LoggerFactory.getLogger(KkClientFactory.class);
private final static String RUNTIME_RESOURCE_NAME = "IAM";
private final static String CATEGORY = "Service";
private final static String REALM_D4S = "d4science";
private final static boolean IS_ROOT_SERVICE = true;
// the singleton obj
private static KkClientFactory singleton = new KkClientFactory();
/**
* keycloak configuration obtained from IS in the private constructor
* using the singleton pattern, it's retrieved from IS only for the first access, then kept in the singleton object
*/
private KeycloakServerConfig config_keycloak;
public static KkClientFactory getSingleton() {
if (singleton == null)
singleton = new KkClientFactory();
return singleton;
}
/**
* Private constructor
* obtains the is_config_keycloak from IS
*/
private KkClientFactory() {
logger.info("Building KeycloakAPICredentials object");
try {
if (this.config_keycloak == null)
setIsKeycloackInstance();
if (this.config_keycloak == null)
setTestKeycloackInstance();
} catch (Exception e) {
logger.error("error obtaining IAM configuration from IS {} ", e);
}
logger.info("KeycloakAPICredentials object built {} - {}", config_keycloak.getServerUrl(), config_keycloak.getRealm() );
}
public void setTestKeycloackInstance() {
this.config_keycloak = KeycloakServerConfig.getTestConfig();
}
public void setIsKeycloackInstance() throws Exception {
this.config_keycloak = lookupPropertiesFromIs(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S, IS_ROOT_SERVICE);
}
public static String encodeClientIdContext(String context) {
return context.replace("/", "%2F");
}
public KeycloackApiClient createtKeycloakInstance(String context) {
return keycloackInstanceFromConfig(this.config_keycloak, context);
}
public static KeycloackApiClient keycloackInstanceFromConfig(KeycloakServerConfig config, String context) {
Keycloak kclient = KeycloakBuilder.builder()
.serverUrl(config.getServerUrl())
.realm(config.getRealm())
.grantType(config.getGrantType())
.clientId(config.getClientId()) //
.clientSecret(config.getClientSecret()).build();
return new KeycloackApiClient(kclient, config.getRealm(), context);
}
public RealmResource getKKRealmForCurrentContext() {
String ctx = SecretManagerProvider.get().getContext();
return getKKRealmForContext(ctx);
}
public RealmResource getKKRealmForContext(String ctx) {
logger.info("Searching client for contex");
KeycloackApiClient keycloackApiClient = createtKeycloakInstance(ctx);
RealmResource realm = keycloackApiClient.kclient.realm(keycloackApiClient.realmName);
return realm;
}
public ClientResource getKKClientForCurrentContext() {
String ctx = SecretManagerProvider.get().getContext();
return getKKClientForContext(ctx);
}
public ClientResource getKKClientForContext(String ctx) {
logger.info("Searching client for contex");
RealmResource realm = getKKRealmForContext(ctx);
List<ClientRepresentation> clients = realm.clients().findByClientId(encodeClientIdContext(ctx));
if (clients.size() == 0) {
return null;
}
String id = clients.get(0).getId();
return realm.clients().get(id);
}
/**
* Read the properties from the infrastructure
*
* @throws Exception
*/
private KeycloakServerConfig lookupPropertiesFromIs(String resource_name, String category, String accessPointName, boolean root_service)
throws Exception {
logger.info("Starting creating KeycloakAPICredentials");
ServiceEndpoint.AccessPoint accessPoint = InfrastrctureServiceClient.getAccesspointFromIS(resource_name,
category, accessPointName, root_service);
if (accessPoint == null) {
String error_log = "Unable to retrieve service endpoint " + accessPointName;
logger.error(error_log);
throw new NotFoundException(error_log);
}
String keycloakURL = accessPoint.address();
String realm = accessPoint.name();
String clientId = accessPoint.username();
String clientSecret = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
KeycloakServerConfig config = new KeycloakServerConfig(keycloakURL, realm, clientId, clientSecret);
logger.info("Found accesspoint URL = " + keycloakURL);
return config;
}
}

View File

@ -2,8 +2,10 @@ package org.gcube.service.idm.controller;
import java.util.List;
import org.gcube.keycloack.KkClientFactory;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.slf4j.LoggerFactory;
@ -12,9 +14,19 @@ public class KKRolesClient {
public static List<RoleRepresentation> getRoles() {
logger.info("Searching users for context");
ClientResource client = KkClientFactory.getSingleton().getKKClientForCurrentContext();
List<RoleRepresentation> roles = client.roles().list();
ClientResource client = KkClientFactory.getSingleton().getKKClient();
RolesResource roles_resource = client.roles();
List<RoleRepresentation> roles = roles_resource.list();
return roles;
}
public static RoleRepresentation getRoleByName(String name) {
logger.info("Searching users for context");
ClientResource client = KkClientFactory.getSingleton().getKKClient();
RolesResource roles_resource = client.roles();
RoleResource r = roles_resource.get(name);
return r.toRepresentation();
}
}

View File

@ -3,47 +3,107 @@ 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.KkClientFactory;
import org.gcube.service.idm.keycloack.KeycloackApiClient;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException;
public class KKUserClient {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKUserClient.class);
public static List<UserRepresentation> getUserByEmail(String email) {
logger.info("Searching user by email: {}", email);
RealmResource realm = KkClientFactory.getSingleton().getKKRealmForCurrentContext();
List<UserRepresentation> users = realm.users()
.searchByEmail(email, true);
public static UsersResource users(){
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UsersResource users = realm.users();
return users;
}
public static List<UserRepresentation> getUserByUsername(String username) {
/**
* Search for users based on the given filters.
*
* @param username a value contained in username
* @param firstName a value contained in first name
* @param lastName a value contained in last name
* @param email a value contained in email
* @param emailVerified whether the email has been verified
* @param idpAlias the alias of the Identity Provider
* @param idpUserId the userId at the Identity Provider
* @param firstResult the position of the first result to retrieve
* @param maxResults the maximum number of results to retrieve
* @param enabled only return enabled or disabled users
* @param briefRepresentation Only return basic information (only guaranteed to
* return id, username, created, first
* and last name, email, enabled state, email
* verification state, federation link, and access.
* Note that it means that namely user attributes,
* required actions, and not before are not
* returned.)
* @return a list of {@link UserRepresentation}
*/
public static List<UserRepresentation> search(String username,
String firstName,
String lastName,
String email,
Boolean emailVerified,
String idpAlias,
String idpUserId,
Integer firstResult,
Integer maxResults,
Boolean enabled,
Boolean briefRepresentation) {
logger.info("Searching users with params");
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
List<UserRepresentation> users = realm.users().search(username, firstName, lastName, email, emailVerified,
idpAlias, idpUserId, firstResult, maxResults, enabled, briefRepresentation);
return users;
}
public static UserRepresentation getUserByEmail(String email) {
logger.info("Searching user by email: {}", email);
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users()
.searchByEmail(email, true).stream().findFirst().orElse(null);
return user;
}
public static UserRepresentation getUserById(String username) {
logger.info("Searching user by username: {}", username);
RealmResource realm = KkClientFactory.getSingleton().getKKRealmForCurrentContext();
List<UserRepresentation> users = realm.users()
.search(username, true);
return users;
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users().search(username).stream().findFirst().orElse(null);
return user;
}
public static UserRepresentation getUserByUsername(String username) {
logger.info("Searching user by username: {}", username);
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users()
.search(username, true).stream().findFirst().orElse(null);
return user;
}
public static List<UserRepresentation> searchUsersByRole(String roleName, Integer firstResult, Integer maxResults) {
logger.info("Searching users by role: {}", roleName);
ClientResource client = KkClientFactory.getSingleton().getKKClientForCurrentContext();
ClientResource client = KkClientFactory.getSingleton().getKKClient();
List<UserRepresentation> users = client.roles().get(roleName)
.getUserMembers(firstResult, maxResults);
return users;
}
public static List<UserRepresentation> users(Integer firstResult, Integer maxResults) {
RealmResource realm = KkClientFactory.getSingleton().getKKRealmForCurrentContext();
public static List<UserRepresentation> users(
Integer firstResult,
Integer maxResults) {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
List<UserRepresentation> users = realm.users()
.list(firstResult, maxResults);
@ -51,7 +111,7 @@ public class KKUserClient {
}
public static List<ClientRepresentation> clients() {
RealmResource realm = KkClientFactory.getSingleton().getKKRealmForCurrentContext();
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
String ctx = SecretManagerProvider.get().getContext();
KeycloackApiClient keycloackApiClient = KkClientFactory.getSingleton()

View File

@ -0,0 +1,172 @@
package org.gcube.service.idm.is;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.security.AuthorizedTasks;
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.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException;
/**
* Utility class to query EndPoints and search for AccessPoints from IS
* @author Alfredo Oliviero (ISTI - CNR)
*/
public class InfrastrctureServiceClient {
private static final Logger logger = LoggerFactory.getLogger(InfrastrctureServiceClient.class);
/**
* obatins from IS the list of ServiceEndpoint matching the parameters
*
* @param resource_name
* @param category
* @param accessPointName
* @param is_root_service
* @return the list of EndPoints matching the parameters
* @throws Exception
*/
public static List<ServiceEndpoint> getEndopintsFromIS(String resource_name, String category,
boolean root_service) {
SimpleQuery query = queryFor(ServiceEndpoint.class);
if (resource_name != null) {
query.addCondition("$resource/Profile/Name/text() eq '" + resource_name + "'");
}
if (category != null){
query.addCondition("$resource/Profile/Category/text() eq '" + category + "'");
}
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
ApplicationContext ctx = ContextProvider.get();
String infra_context = "/" + ctx.container().configuration().infrastructure();
Secret secret = ctx.container().authorizationProvider().getSecretForContext(infra_context);
List<ServiceEndpoint> endpoints = null;
try {
if (root_service) {
endpoints = AuthorizedTasks.executeSafely(() -> {
// esegui la query
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}, secret);
} else {
endpoints = client.submit(query);
}
} catch (Throwable e) {
e.printStackTrace();
}
return endpoints;
}
/**
* obatains the list of AccessPoints matching the parameters
*
* @param resource_name
* @param category
* @param accessPointName
* @param is_root_service
* @return the list of AccessPoints
* @throws Exception
*/
public static List<ServiceEndpoint.AccessPoint> getAccessPointsFromIS(String resource_name, String category,
String accessPointName, boolean is_root_service) throws Exception {
List<ServiceEndpoint> resources = getEndopintsFromIS(resource_name, category, is_root_service);
if (resources.size() == 0) {
logger.error("There is no Runtime Resource having name " + resource_name + " and Category "
+ category + " in this scope.");
return null;
}
List<ServiceEndpoint.AccessPoint> response = new ArrayList<ServiceEndpoint.AccessPoint>();
resources.forEach(res -> {
Stream<ServiceEndpoint.AccessPoint> access_points_res = res.profile().accessPoints().stream();
if (accessPointName == null) {
access_points_res = access_points_res.filter(ap -> ap.name().equals(accessPointName));
}
access_points_res.forEach(a -> response.add(a));
});
return response;
}
/**
* obatains the list of AccessPoints matching the parameters, and returns the first one
*
* @param resource_name
* @param category
* @param accessPointName
* @return an AccessPoints matching the parameters
* @throws Exception
*/
public static ServiceEndpoint.AccessPoint getAccessPointFromIS(String resource_name, String category,
String accessPointName, boolean root_service) throws Exception {
List<ServiceEndpoint.AccessPoint> access_points = getAccessPointsFromIS(resource_name, category, accessPointName, root_service);
if (access_points.size() == 0) {
logger.error("Unable to retrieve service endpoint " + accessPointName);
return null;
}
return access_points.get(0);
}
/**
* Reads the service configuration from the IS
* @param resourceName
* @param category
* @param accessPointName
* @param is_root_service
* @return
* @throws Exception
*/
public static IsServerConfig serviceConfigFromIS(String resourceName, String category, String accessPointName, boolean is_root_service)
throws Exception {
logger.info("Starting creating service credentials");
ServiceEndpoint.AccessPoint accessPoint = InfrastrctureServiceClient.getAccessPointFromIS(resourceName,
category, accessPointName, is_root_service);
if (accessPoint == null) {
String error_log = "Unable to retrieve service endpoint " + accessPointName;
logger.error(error_log);
throw new NotFoundException(error_log);
}
String service_url = accessPoint.address();
String name = accessPoint.name();
String clientId = accessPoint.username();
String clientSecret = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
IsServerConfig config = new IsServerConfig(service_url, name, clientId, clientSecret);
logger.info("Found AccessPoint URL = " + service_url);
return config;
}
}

View File

@ -1,8 +1,8 @@
package org.gcube.keycloack;
package org.gcube.service.idm.is;
import org.keycloak.OAuth2Constants;
public class KeycloakServerConfig {
public class IsServerConfig {
private String serverUrl;
private String realm;
private String clientId;
@ -30,27 +30,16 @@ public class KeycloakServerConfig {
return grantType;
}
public KeycloakServerConfig(String serverUrl, String realm, String clientId, String clientSecret) {
public IsServerConfig(String serverUrl, String realm, String clientId, String clientSecret) {
this.serverUrl = serverUrl;
this.realm = realm;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public KeycloakServerConfig(String serverUrl, String realm, String clientId, String clientSecret,
public IsServerConfig(String serverUrl, String realm, String clientId, String clientSecret,
String grantType) {
this(serverUrl, realm, clientId, clientSecret);
this.grantType = grantType;
}
//TODO: REMOVE
static KeycloakServerConfig getTestConfig(){
String serverUrl = "https://accounts.dev.d4science.org/auth";
String realm = "d4science";
String clientId = "id.d4science.org";
String clientSecret = "09c26f24-3c65-4039-9fa0-e5cc4f4032cd";
return new KeycloakServerConfig(serverUrl, realm, clientId, clientSecret);
}
}

View File

@ -1,96 +0,0 @@
package org.gcube.service.idm.is.client;
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor;
import java.util.List;
import org.gcube.common.resources.gcore.ServiceEndpoint;
// import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.common.security.AuthorizedTasks;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.gcube.common.security.secrets.Secret;
public class InfrastrctureServiceClient {
private static final Logger logger = LoggerFactory.getLogger(InfrastrctureServiceClient.class);
/**
* Retrieve endpoints information from IS for DB
*
* @return list of endpoints for ckan database
* @throws Throwable
*/
public static List<ServiceEndpoint> getEndopintsFromIS(String resource_name, String category,
boolean root_service) {
SimpleQuery query = queryFor(ServiceEndpoint.class);
query.addCondition("$resource/Profile/Name/text() eq '" + resource_name + "'");
query.addCondition("$resource/Profile/Category/text() eq '" + category + "'");
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
ApplicationContext ctx = ContextProvider.get();
String infra_context = "/" + ctx.container().configuration().infrastructure();
Secret secret = ctx.container().authorizationProvider().getSecretForContext(infra_context);
List<ServiceEndpoint> endpoints = null;
try {
if (root_service) {
endpoints = AuthorizedTasks.executeSafely(() -> {
// esegui la query
List<ServiceEndpoint> toReturn = client.submit(query);
return toReturn;
}, secret);
} else {
endpoints = client.submit(query);
}
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return endpoints;
}
/**
* @param resource_name
* @param category
* @param accessPointName
* @return
* @throws Exception
*/
public static ServiceEndpoint.AccessPoint getAccesspointFromIS(String resource_name, String category,
String accessPointName, boolean root_service) throws Exception {
List<ServiceEndpoint> resources = getEndopintsFromIS(resource_name, category, root_service);
if (resources.size() == 0) {
logger.error("There is no Runtime Resource having name " + resource_name + " and Category "
+ category + " in this scope.");
return null;
}
for (ServiceEndpoint res : resources) {
ServiceEndpoint.AccessPoint accessPoint = res.profile().accessPoints().stream()
.filter(ap -> ap.name().equals(accessPointName))
.findFirst().orElse(null);
if (accessPoint != null) {
return accessPoint;
}
}
String error_log = "Unable to retrieve service endpoint " + accessPointName;
logger.error(error_log);
return null;
}
}

View File

@ -1,4 +1,4 @@
package org.gcube.keycloack;
package org.gcube.service.idm.keycloack;
public class ErrorMessages {

View File

@ -1,4 +1,4 @@
package org.gcube.keycloack;
package org.gcube.service.idm.keycloack;
import org.keycloak.admin.client.Keycloak;

View File

@ -0,0 +1,131 @@
package org.gcube.service.idm.keycloack;
import java.util.List;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.is.InfrastrctureServiceClient;
import org.gcube.service.idm.is.IsServerConfig;
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.RealmResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KkClientFactory {
private static final Logger logger = LoggerFactory.getLogger(KkClientFactory.class);
private final static String RUNTIME_RESOURCE_NAME = "IAM";
private final static String CATEGORY = "Service";
private final static String REALM_D4S = "d4science";
private final static boolean IS_ROOT_SERVICE = true;
// the singleton obj
private static KkClientFactory singleton = new KkClientFactory();
/**
* keycloak configuration obtained from IS in the private constructor
* using the singleton pattern, it's retrieved from IS only for the first
* access, then kept in the singleton object
*/
private IsServerConfig config;
public static KkClientFactory getSingleton() {
if (singleton == null)
singleton = new KkClientFactory();
return singleton;
}
/**
* Private constructor
* obtains the config from IS
*/
private KkClientFactory() {
logger.info("Building KeycloakAPICredentials object");
try {
if (this.config == null) {
this.config = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S,
IS_ROOT_SERVICE);
}
// if (this.config_keycloak == null)
// this.config = IsServerConfig.getTestConfig();
} catch (
Exception e) {
logger.error("error obtaining IAM configuration from IS {} ", e);
}
logger.info("KeycloakAPICredentials object built {} - {}", config.getServerUrl(), config.getRealm());
}
public void setIsConfig() throws Exception {
this.config = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S,
IS_ROOT_SERVICE);
}
public static String encodeClientIdContext(String context) {
return context.replace("/", "%2F");
}
public KeycloackApiClient createtKeycloakInstance(String context) {
return createtKeycloakInstance(this.config, context);
}
public static KeycloackApiClient createtKeycloakInstance(IsServerConfig config, String context) {
Keycloak kclient = KeycloakBuilder.builder()
.serverUrl(config.getServerUrl())
.realm(config.getRealm())
.grantType(config.getGrantType())
.clientId(config.getClientId()) //
.clientSecret(config.getClientSecret()).build();
return new KeycloackApiClient(kclient, config.getRealm(), context);
}
public RealmResource getKKRealm() {
String ctx = SecretManagerProvider.get().getContext();
return getKKRealm(ctx);
}
public RealmResource getKKRealm(String ctx) {
logger.info("Searching client for contex");
KeycloackApiClient keycloackApiClient = createtKeycloakInstance(ctx);
RealmResource realm = keycloackApiClient.kclient.realm(keycloackApiClient.realmName);
return realm;
}
public ClientResource getKKClient() {
String ctx = SecretManagerProvider.get().getContext();
return getKKClient(ctx);
}
public ClientResource getKKClient(String ctx) {
logger.info("Searching client for contex");
RealmResource realm = getKKRealm(ctx);
List<ClientRepresentation> clients = realm.clients().findByClientId(encodeClientIdContext(ctx));
if (clients.size() == 0) {
return null;
}
String id = clients.get(0).getId();
return realm.clients().get(id);
}
// TODO: REMOVE
static IsServerConfig getTestConfig() {
String serverUrl = "https://accounts.dev.d4science.org/auth";
String realm = "d4science";
String clientId = "id.d4science.org";
String clientSecret = "09c26f24-3c65-4039-9fa0-e5cc4f4032cd";
return new IsServerConfig(serverUrl, realm, clientId, clientSecret);
}
}

View File

@ -0,0 +1,89 @@
package org.gcube.service.idm.liferay;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.service.idm.is.InfrastrctureServiceClient;
import org.gcube.service.idm.is.IsServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException;
public class LiferayClientFactory {
private static final Logger logger = LoggerFactory.getLogger(LoggerFactory.class);
// Service endpoint properties
private final static String RUNTIME_RESOURCE_NAME = "D4Science Infrastructure Gateway";
private final static String CATEGORY = "Portal";
private final static String REALM_D4S = "d4science";
private final static boolean IS_ROOT_SERVICE = true;
private static LiferayClientFactory singleton = new LiferayClientFactory();
/**
* keycloak configuration obtained from IS in the private constructor
* using the singleton pattern, it's retrieved from IS only for the first access, then kept in the singleton object
*/
private IsServerConfig config;
public static LiferayClientFactory getSingleton() {
if (singleton == null)
singleton = new LiferayClientFactory();
return singleton;
}
/**
* Private constructor
* obtains the config from IS
*/
private LiferayClientFactory() {
logger.info("Building LiferayClientFactory object");
try {
if (this.config == null)
setIsInstance();
// if (this.config_keycloak == null)
// setTestKeycloackInstance();
} catch (Exception e) {
logger.error("error obtaining Liferay configuration from IS {} ", e);
}
logger.info("Liferay object built {} - {}", config.getServerUrl(), config.getRealm() );
}
public void setIsInstance() throws Exception {
this.config = lookupPropertiesFromIs(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S, IS_ROOT_SERVICE);
}
/**
* Read the properties from the infrastructure
*
* @throws Exception
*/
private IsServerConfig lookupPropertiesFromIs(String resource_name, String category, String accessPointName, boolean root_service)
throws Exception {
logger.info("Starting creating KeycloakAPICredentials");
ServiceEndpoint.AccessPoint accessPoint = InfrastrctureServiceClient.getAccessPointFromIS(resource_name,
category, accessPointName, root_service);
if (accessPoint == null) {
String error_log = "Unable to retrieve service endpoint " + accessPointName;
logger.error(error_log);
throw new NotFoundException(error_log);
}
String service_url = accessPoint.address();
String name = accessPoint.name();
String clientId = accessPoint.username();
String clientSecret = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
IsServerConfig config = new IsServerConfig(service_url, name, clientId, clientSecret);
logger.info("Found accesspoint URL = " + service_url);
return config;
}
}

View File

@ -1,17 +1,17 @@
package org.gcube.service.idm.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.KKRolesClient;
import org.gcube.service.idm.controller.KKUserClient;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.gcube.service.rest.ResponseBeanPaginated;
import org.gcube.smartgears.annotations.ManagedBy;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
@ -19,29 +19,39 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.constraints.Min;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@ManagedBy(IdMManager.class)
@Path("roles")
public class RolesAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(RolesAPI.class);
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(RolesAPI.class);
@GET
@Path("/")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response roles() {
@Produces(MediaType.APPLICATION_JSON)
public Response search(@QueryParam("search") @DefaultValue("") String search,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults,
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();;
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try {
List<RoleRepresentation> roles = KKRolesClient.getRoles();
ClientResource client = KkClientFactory.getSingleton().getKKClient();
List<RoleRepresentation> roles = client.roles().list(search, firstResult, maxResults, briefRepresentation);
responseBean.setResult(roles);
responseBean.setSuccess(true);
@ -51,6 +61,78 @@ public class RolesAPI {
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("/{name}")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response role(
@PathParam("name") String role_name) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
RoleRepresentation role = KKRolesClient.getRoleByName(role_name);
responseBean.setResult(role);
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("/{role_name}/users")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response usersForRole(
@PathParam("role_name") String role_name,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try {
ClientResource client = KkClientFactory.getSingleton().getKKClient();
RolesResource roles_resource = client.roles();
RoleResource r = roles_resource.get(role_name);
List<UserRepresentation> users = r.getUserMembers(firstResult, maxResults);
responseBean.setResult(users);
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();

View File

@ -0,0 +1,233 @@
package org.gcube.service.idm.rest;
import java.lang.reflect.MalformedParametersException;
import java.util.List;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.KKUserClient;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.gcube.service.rest.ResponseBeanPaginated;
import org.gcube.smartgears.annotations.ManagedBy;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.representations.idm.UserRepresentation;
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.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@ManagedBy(IdMManager.class)
@Path("users")
public class UserApi {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserApi.class);
@GET
@Path("/me/owner")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getCurrentUsers() {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
// UserResource user = KKUserClient.getUserById();
responseBean.setResult(owner);
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("/{username}")
// @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
// public Response getUser(
// @PathParam("username") String username) {
// return getUserParameter(username, null);
// }
@GET
@Path("/{username}/{parameter}")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getUserParameter(
@PathParam("username") String username,
@PathParam("parameter") String parameter) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
if (username.equals("me")) {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
username = owner.getId();
}
try {
UserRepresentation user = KKUserClient.getUserByUsername(username);
if (parameter == null)
responseBean.setResult(user);
// UserResource user = KKUserClient.getUserById();
if (parameter.equals("profile") || parameter == null)
responseBean.setResult(user);
else if (parameter.equals("email"))
responseBean.setResult(user.getEmail());
else if (parameter.equals("roles_realm"))
responseBean.setResult(user.getRealmRoles());
else if (parameter.equals("roles_clients"))
responseBean.setResult(user.getClientRoles());
else if (parameter.equals("groups"))
responseBean.setResult(user.getGroups());
else if (parameter.equals("id"))
responseBean.setResult(user.getId());
else if (parameter.equals("username"))
responseBean.setResult(user.getUsername());
else if (parameter.equals("name"))
responseBean.setResult(user.getFirstName() + " " + user.getLastName());
else if (parameter.equals("attributes"))
responseBean.setResult(user.getAttributes());
else if (parameter.equals("organization"))
responseBean.setResult(user.getAttributes().get("organizations"));
else
throw new MalformedParametersException("unknow parameter " + parameter);
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("/search")
@Produces(MediaType.APPLICATION_JSON)
public Response search(@QueryParam("username") String username,
@QueryParam("firstName") String firstName,
@QueryParam("lastName") String lastName,
@QueryParam("email") String email,
@QueryParam("emailVerified") @DefaultValue("true") Boolean emailVerified,
@QueryParam("idpAlias") String idpAlias,
@QueryParam("idpUserId") String idpUserId,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults,
@QueryParam("enabled") @DefaultValue("true") Boolean enabled,
@QueryParam("briefRepresentation") @DefaultValue("true") Boolean briefRepresentation) {
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
List<UserRepresentation> users = realm.users().search(username, firstName, lastName, email, emailVerified,
idpAlias, idpUserId, firstResult, maxResults, enabled, briefRepresentation);
responseBean.setResult(users);
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("/{username}")
@Produces(MediaType.APPLICATION_JSON)
public Response getById(@PathParam("username") String id) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
UserRepresentation user = KKUserClient.getUserById(id);
responseBean.setResult(user);
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();
}
}
}

View File

@ -5,27 +5,19 @@ 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.keycloack.ErrorMessages;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.gcube.service.rest.ResponseBeanPaginated;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
@ -35,12 +27,18 @@ 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.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.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@ManagedBy(IdMManager.class)
@Path("users")
@Path("social/users")
// @ResourceGroup("Users APIs")
// @ResourceLabel("Greetings APIs")
// @RequestHeaders({
@ -48,7 +46,7 @@ import jakarta.ws.rs.core.MediaType;
// 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 org.slf4j.Logger logger = LoggerFactory.getLogger(UsersSocialAPI.class);
// private static final List<String> GLOBAL_ROLES_ALLOWED_BY_LOCAL_CALL_METHOD =
// Arrays.asList("DataMiner-Manager",
@ -59,11 +57,11 @@ public class UsersSocialAPI {
@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("10000") @Min(value = 0, message = "quantity cannot be negative") int maxResults) {
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult > 0 || maxResults > 0) {
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
@ -100,22 +98,37 @@ public class UsersSocialAPI {
@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) {
@QueryParam("emailVerified") Boolean emailVerified,
@QueryParam("enabled") Boolean enabled,
@QueryParam("briefRepresentation") @DefaultValue("true") Boolean briefRepresentation,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
Map<String, String> usernamesAndFullnames = new HashMap<String, String>();
ResponseBean responseBean;
if (firstResult != null || maxResults != null ) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try {
UsersResource users_resource = KKUserClient.users();
List<UserRepresentation> users = users_resource.search(emailVerified, firstResult, maxResults, enabled,
briefRepresentation);
List<UserRepresentation> users = KKUserClient.users(firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernamesAndFullnames.put(user.getUsername(), user.getEmail());
}
if (briefRepresentation) {
Map<String, String> usernamesAndFullnames = new HashMap<String, String>();
users.forEach(user -> usernamesAndFullnames.put(user.getUsername(), user.getEmail()));
responseBean.setResult(usernamesAndFullnames);
} else {
Map<String, Object> usernamesAndUsers = new HashMap<String, Object>();
users.forEach(user -> usernamesAndUsers.put(user.getUsername(), user));
responseBean.setResult(usernamesAndUsers);
}
responseBean.setResult(usernamesAndFullnames);
responseBean.setSuccess(true);
} catch (Exception e) {
logger.error("Unable to retrieve users", e);
@ -272,12 +285,18 @@ public class UsersSocialAPI {
@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) {
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
List<String> usernames = new ArrayList<String>();
try {
List<UserRepresentation> users = KKUserClient.users(firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
@ -312,8 +331,8 @@ public class UsersSocialAPI {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
List<UserRepresentation> users = KKUserClient.getUserByUsername(username);
boolean user_exists = users != null && users.size() > 0;
UserRepresentation user = KKUserClient.getUserByUsername(username);
boolean user_exists = user != null;
responseBean.setResult(user_exists);
responseBean.setSuccess(true);

View File

@ -0,0 +1,64 @@
package org.gcube.service.idm.serializers;
import java.io.IOException;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
/**
* Jackson serializer for ServiceEndpoint.AccessPoint
*
* @author Alfredo Oliviero (ISTI-CNR)
*
*/
public class ServiceEndpointAccessPointSerializer extends StdSerializer<ServiceEndpoint.AccessPoint> {
protected ServiceEndpointAccessPointSerializer(Class<ServiceEndpoint.AccessPoint> t) {
super(t);
}
public ServiceEndpointAccessPointSerializer() {
super(ServiceEndpoint.AccessPoint.class, true);
}
@Override
public void serialize(ServiceEndpoint.AccessPoint accessPoint, JsonGenerator jgen, SerializerProvider provider)
throws IOException {
jgen.writeStartObject();
String error = null;
String clientSecret = null;
try {
clientSecret = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
} catch (Exception e) {
error = e.getMessage();
}
jgen.writeStringField("address", accessPoint.address());
jgen.writeStringField("name", accessPoint.name());
jgen.writeStringField("description", accessPoint.description());
try {
jgen.writeStringField("username", accessPoint.username());
} catch (Exception e) {
jgen.writeStringField("username", null);
}
try {
jgen.writeStringField("tostring", accessPoint.toString());
} catch (Exception e) {
jgen.writeStringField("tostring", null);
}
if (error != null) {
jgen.writeStringField("key_error", error);
jgen.writeBooleanField("key_decoded", false);
} else {
jgen.writeBooleanField("key_decoded", true);
}
jgen.writeEndObject();
}
}

View File

@ -1,7 +1,5 @@
package org.gcube.service.rest;
import java.io.Serializable;
/**
* Response bean
*

26
todo.md Normal file
View File

@ -0,0 +1,26 @@
# CONFIGURAZIONE
* come ottengo la configurazione di keycloak? devo interrogare IS? file di configurazione?
* lucio dice di chiedere a IS
* luca dice che non va chiesto a IS ma ha un indirizzo fisso che ottengo dal contesto
* [x] verificare configurazione keycloak
* [ ] caching realm e client keycloak?
risoluzione liferay
endpoint "D4science Infrastructure Gateway"
service "Portal"
# API
* [ ] getEmail: non trovo in owner. da dove si prende?
* [ ] accesso al profilo utente
* [ ] come risolvere liferay?
* [ ] implementare metodi relativi a profile
* [ ] API full rest
* [ ] esecuzione in container
* [ ] implementare tutta la gestione profilo
* [ ] leggere parametri da file di container.ini
* [ ] rivedere gestione errori
* [x] formalizzare formato risposta