api rest for users, clients, social. implemented the integration of liferay client for user profile

This commit is contained in:
Alfredo Oliviero 2024-04-17 16:05:10 +02:00
parent d995edb5cd
commit 35689417c0
24 changed files with 1646 additions and 646 deletions

View File

@ -0,0 +1,211 @@
package org.gcube.service.idm.controller;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.keycloak.admin.client.CreatedResponseUtil;
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.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.WebApplicationException;
public class AdminKeycloakController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AdminKeycloakController.class);
// https://gist.github.com/thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b
public static UserRepresentation createUser(String username, String email, String password, String firstName,
String lastName, Map<String, List<String>> attributes, List<String> roles) throws WebApplicationException {
UserRepresentation newUser = new UserRepresentation();
newUser.setEnabled(true);
newUser.setUsername(username);
newUser.setFirstName(firstName);
newUser.setLastName(lastName);
newUser.setEmail(email);
if (attributes != null) {
// user.setAttributes(Collections.singletonMap("origin",
// Arrays.asList("demo")));
newUser.setAttributes(attributes);
}
RealmResource realmResource = KkClientFactory.getSingleton().getKKRealm();
UsersResource usersRessource = realmResource.users();
// Response response = usersRessource.create(user);
// System.out.printf("Repsonse: %s %s%n", response.getStatus(),
// response.getStatusInfo());
// System.out.println(response.getLocation());
// String userId = CreatedResponseUtil.getCreatedId(response);
String newUserId = null;
// throws exception if creationResponse is failed
try {
javax.ws.rs.core.Response creationResponse = usersRessource.create(newUser);
newUserId = CreatedResponseUtil.getCreatedId(creationResponse);
} catch (javax.ws.rs.WebApplicationException e) {
logger.error("error creating user {} - {}", newUser, e.getMessage());
e.printStackTrace();
throw new WebApplicationException(e.getMessage());
}
logger.info("created user {}", newUser);
CredentialRepresentation passwordCred = new CredentialRepresentation();
passwordCred.setTemporary(false);
passwordCred.setType(CredentialRepresentation.PASSWORD);
passwordCred.setValue(password);
UserResource userResource = usersRessource.get(newUserId);
userResource.resetPassword(passwordCred);
// // Get realm role "tester" (requires view-realm role)
RoleRepresentation testerRealmRole = realmResource.roles()//
.get("tester").toRepresentation();
//
// // Assign realm role tester to user
userResource.roles().realmLevel() //
.add(Arrays.asList(testerRealmRole));
//
ClientResource client = KkClientFactory.getSingleton().getKKClient();
if (roles != null) {
List<RoleRepresentation> listRolesRepr = new ArrayList<>();
roles.forEach(role -> listRolesRepr.add(client.roles().get(role).toRepresentation()));
//
// // // Assign client level role to user
// userResource.roles() //
// .clientLevel(client.get.getId()).add(roles);
}
return userResource.toRepresentation();
}
// https://gist.github.com/thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b
public static ClientRepresentation createClient(
String id,
String clientId,
String name,
String description,
String rootUrl,
String adminUrl,
String baseUrl,
Boolean surrogateAuthRequired,
Boolean enabled,
Boolean alwaysDisplayInConsole,
String clientAuthenticatorType,
String secret,
String registrationAccessToken,
// @Deprecated String[] defaultRoles,
List<String> redirectUris,
List<String> webOrigins,
Integer notBefore,
Boolean bearerOnly,
Boolean consentRequired,
Boolean standardFlowEnabled,
Boolean implicitFlowEnabled,
Boolean directAccessGrantsEnabled,
Boolean serviceAccountsEnabled,
// Boolean oauth2DeviceAuthorizationGrantEnabled, no getter/setter
Boolean authorizationServicesEnabled,
// @Deprecated Boolean directGrantsOnly,
Boolean publicClient,
Boolean frontchannelLogout,
String protocol,
Map<String, String> attributes,
Map<String, String> authenticationFlowBindingOverrides,
Boolean fullScopeAllowed,
Integer nodeReRegistrationTimeout,
Map<String, Integer> registeredNodes,
List<ProtocolMapperRepresentation> protocolMappers,
// @Deprecated String clientTemplate,
// @Deprecated private Boolean useTemplateConfig,
// @Deprecated private Boolean useTemplateScope,
// @Deprecated private Boolean useTemplateMappers,
List<String> defaultClientScopes,
List<String> optionalClientScopes,
// private ResourceServerRepresentation authorizationSettings,
// private Map<String, Boolean> access,
String origin
) {
ClientRepresentation newClient = new ClientRepresentation();
newClient.setId(id);
newClient.setClientId(clientId);
newClient.setName(name);
newClient.setDescription(description);
newClient.setRootUrl(rootUrl);
newClient.setAdminUrl(adminUrl);
newClient.setBaseUrl(baseUrl);
newClient.setSurrogateAuthRequired(surrogateAuthRequired);
newClient.setEnabled(enabled);
newClient.setAlwaysDisplayInConsole(alwaysDisplayInConsole);
newClient.setClientAuthenticatorType(clientAuthenticatorType);
newClient.setSecret(secret);
newClient.setRegistrationAccessToken(registrationAccessToken);
newClient.setRedirectUris(redirectUris);
newClient.setWebOrigins(webOrigins);
newClient.setNotBefore(notBefore);
newClient.setConsentRequired(consentRequired);
newClient.setStandardFlowEnabled(standardFlowEnabled);
newClient.setImplicitFlowEnabled(implicitFlowEnabled);
newClient.setDirectAccessGrantsEnabled(directAccessGrantsEnabled);
newClient.setServiceAccountsEnabled(serviceAccountsEnabled);
newClient.setAuthorizationServicesEnabled(authorizationServicesEnabled);
newClient.setPublicClient(publicClient);
newClient.setFrontchannelLogout(frontchannelLogout);
newClient.setProtocol(protocol);
newClient.setAttributes(attributes);
newClient.setAuthenticationFlowBindingOverrides(authenticationFlowBindingOverrides);
newClient.setFullScopeAllowed(fullScopeAllowed);
newClient.setNodeReRegistrationTimeout(nodeReRegistrationTimeout);
newClient.setRegisteredNodes(registeredNodes);
newClient.setProtocolMappers(protocolMappers);
newClient.setDefaultClientScopes(defaultClientScopes);
newClient.setOptionalClientScopes(optionalClientScopes);
newClient.setOrigin(origin);
return createClient(newClient);
}
public static ClientRepresentation createClient(ClientRepresentation newClient) {
RealmResource realmResource = KkClientFactory.getSingleton().getKKRealm();
ClientsResource clientsResource = realmResource.clients();
String newClientId = null;
// throws exception if creationResponse is failed
try {
javax.ws.rs.core.Response creationResponse = clientsResource.create(newClient);
newClientId = CreatedResponseUtil.getCreatedId(creationResponse);
} catch (javax.ws.rs.WebApplicationException e) {
logger.error("error creating client {} - {}", newClient, e.getMessage());
e.printStackTrace();
throw new WebApplicationException(e.getMessage());
}
logger.info("created user {}", newClient);
ClientResource client = clientsResource.get(newClientId);
return client.toRepresentation();
}
}

View File

@ -0,0 +1,82 @@
package org.gcube.service.idm.controller;
import java.util.List;
import java.util.Map;
import org.gcube.common.keycloak.model.ModelUtils;
import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret;
public class AuthController {
public final static String IDM_SERVICE_READ = "idm-service-read";
public final static String IDM_SERVICE_ADMIN = "idm-service-admin";
public final static List<String> ACCESS_READ_ROLES = List.of(IDM_SERVICE_READ, IDM_SERVICE_ADMIN);
public final static List<String> ACCESS_ADMIN_ROLES = List.of(IDM_SERVICE_READ);
public static String getAccessToken() {
Map<String, String> authorizations = SecretManagerProvider.get().getHTTPAuthorizationHeaders();
String access_token = authorizations.get("Authorization").replace("Bearer", "").trim();
return access_token;
}
public static Owner getOwner() {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
return owner;
}
public static boolean checkRealmRole(String realm_role) {
String access_token = getAccessToken();
return checkRealmRole(realm_role, access_token);
}
public static boolean checkRealmRole(String realm_role, String access_token) {
try {
return ModelUtils.getAccessTokenFrom(access_token).getRealmAccess().getRoles().contains(realm_role);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public static boolean checkContextRole(String context_role) {
Owner owner = getOwner();
return checkContextRole(context_role, owner);
}
public static boolean checkContextRole(String context_role, Owner owner) {
return owner.getRoles().contains(context_role);
}
public static boolean checkRole(String role) {
return checkContextRole(role) || checkRealmRole(role);
}
public static boolean checkAnyRole(List<String> roles) {
String access_token = getAccessToken();
Owner owner = getOwner();
for (String role : roles){
if ( checkContextRole(role, owner) || checkRealmRole(role, access_token)){
return true;
}
}
return false;
}
public static boolean userIsMe(String username) {
Owner owner = getOwner();
return userIsMe(username, owner);
}
public static boolean userIsMe(String username, Owner owner) {
return !owner.isApplication() && owner.getId().equals(username);
}
}

View File

@ -0,0 +1,35 @@
package org.gcube.service.idm.controller;
import java.util.HashMap;
import java.util.Map;
import org.gcube.service.idm.serializers.ContextSerializator;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
public class JWTController {
public static Map<String, Object> decodeJwtToken(String token)
throws JsonMappingException, JsonProcessingException {
DecodedJWT decodedJWT = JWT.decode(token);
String headerJson = ContextSerializator.decodeBase64String(decodedJWT.getHeader());
String payloadJson = ContextSerializator.decodeBase64String(decodedJWT.getPayload());
// String signatureJson =
// ContextSerializator.decodeBase64String(decodedJWT.getSignature());
Map<String, Object> decoded = new HashMap<String, Object>();
decoded.put("jwt_token", token);
decoded.put("token", decodedJWT.getToken());
decoded.put("header", ContextSerializator.jsonStringToHasmap(headerJson));
decoded.put("payload", ContextSerializator.jsonStringToHasmap(payloadJson));
// decoded.put("signature",
// ContextSerializator.jsonStringToHasmap(signatureJson));
decoded.put("decodedJWT", decodedJWT);
return decoded;
}
}

View File

@ -13,18 +13,19 @@ import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotFoundException;
public class KKUserClient {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKUserClient.class);
public class KCUserController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KCUserController.class);
public static UsersResource users(){
public static UsersResource users() {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UsersResource users = realm.users();
return users;
}
/**
/**
* Search for users based on the given filters.
*
* @param username a value contained in username
@ -71,6 +72,9 @@ public class KKUserClient {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users()
.searchByEmail(email, true).stream().findFirst().orElse(null);
if (user == null) {
throw new NotFoundException("cannot retrieve user for email" + email);
}
return user;
}
@ -79,6 +83,9 @@ public class KKUserClient {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users().search(username).stream().findFirst().orElse(null);
if (user == null) {
throw new NotFoundException("cannot retrieve user " + username);
}
return user;
}
@ -88,9 +95,32 @@ public class KKUserClient {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UserRepresentation user = realm.users()
.search(username, true).stream().findFirst().orElse(null);
if (user == null) {
throw new NotFoundException("cannot retrieve user " + username);
}
return user;
}
public static UserResource getUserResourceByUsername(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);
if (user == null) {
throw new NotFoundException("cannot retrieve user " + username);
}
UserResource userRes = realm.users().get(user.getId());
if (userRes == null) {
throw new NotFoundException("cannot retrieve user " + username);
}
return userRes;
}
public static List<UserRepresentation> searchUsersByRole(String roleName, Integer firstResult, Integer maxResults) {
logger.info("Searching users by role: {}", roleName);
ClientResource client = KkClientFactory.getSingleton().getKKClient();
@ -120,4 +150,43 @@ public class KKUserClient {
List<ClientRepresentation> clients = realm.clients().findByClientId(keycloackApiClient.clientIdContext);
return clients;
}
public static Object getUserParameter(String username, String parameter) {
UserRepresentation user = getUserByUsername(username);
if (user == null) {
throw new NotFoundException("cannot retrieve user " + username);
}
if (parameter == null)
return user;
else if (parameter.equals("email"))
return user.getEmail();
else if (parameter.equals("roles_realm"))
return user.getRealmRoles();
else if (parameter.equals("roles_clients"))
return user.getClientRoles();
else if (parameter.equals("groups"))
return user.getGroups();
else if (parameter.equals("id"))
return user.getId();
else if (parameter.equals("username"))
return user.getUsername();
else if (parameter.equals("name"))
return user.getFirstName() + " " + user.getLastName();
else if (parameter.equals("attributes"))
return user.getAttributes();
else
throw new BadRequestException("unknow parameter " + parameter);
}
}

View File

@ -9,8 +9,10 @@ import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.representations.idm.RoleRepresentation;
import org.slf4j.LoggerFactory;
public class KKRolesClient {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKRolesClient.class);
import jakarta.ws.rs.NotFoundException;
public class KKRolesController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKRolesController.class);
public static List<RoleRepresentation> getRoles() {
logger.info("Searching users for context");
@ -25,8 +27,12 @@ public class KKRolesClient {
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();
RoleResource role = roles_resource.get(name);
if (role == null) {
throw new NotFoundException("cannot retrieve role " + name);
}
return role.toRepresentation();
}
}

View File

@ -0,0 +1,95 @@
package org.gcube.service.idm.controller;
import java.rmi.ServerException;
import org.gcube.service.idm.liferay.LiferayClientFactory;
import org.gcube.vomanagement.usermanagement.exception.UserManagementSystemException;
import org.gcube.vomanagement.usermanagement.exception.UserRetrievalFault;
import org.gcube.vomanagement.usermanagement.impl.ws.LiferayWSUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.ServiceUnavailableException;
public class LiferayProfileClient {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(LiferayProfileClient.class);
public static GCubeUser getUserProfile(long id) {
String errormsg = "cannot retrieve user with id " + id;
try {
LiferayWSUserManager client = LiferayClientFactory.getSingleton().getClient();
GCubeUser user = client.getUserById(id);
if (user == null) {
throw new NotFoundException(errormsg);
}
return user;
} catch (NotFoundException | ServerException | UserManagementSystemException e) {
e.printStackTrace();
throw new ServiceUnavailableException(errormsg);
} catch (UserRetrievalFault e) {
logger.warn(errormsg);
e.printStackTrace();
throw new NotFoundException(errormsg);
}
}
public static GCubeUser getUserProfileByUsername(String username) {
String errormsg = "cannot retrieve user with username " + username;
try {
LiferayWSUserManager client = LiferayClientFactory.getSingleton().getClient();
GCubeUser user = client.getUserByUsername(username);
if (user == null) {
throw new NotFoundException(errormsg);
}
return user;
} catch (UserManagementSystemException e) {
logger.error(errormsg);
e.printStackTrace();
throw new ServiceUnavailableException(errormsg);
} catch (UserRetrievalFault e) {
logger.error(errormsg);
e.printStackTrace();
throw new NotFoundException(errormsg);
} catch (Exception e) {
logger.error(errormsg);
e.printStackTrace();
throw new ServiceUnavailableException(errormsg);
}
}
public static GCubeUser getUserProfileByEmail(String email) {
String errormsg = "cannot retrieve user with email " + email;
try {
LiferayWSUserManager client = LiferayClientFactory.getSingleton().getClient();
GCubeUser user = client.getUserByEmail(email);
if (user == null) {
throw new NotFoundException(errormsg);
}
return user;
} catch (UserManagementSystemException e) {
e.printStackTrace();
throw new ServiceUnavailableException(errormsg);
} catch (UserRetrievalFault e) {
logger.warn(errormsg);
e.printStackTrace();
throw new NotFoundException(errormsg);
} catch (Exception e) {
logger.warn(errormsg);
e.printStackTrace();
throw new ServiceUnavailableException(errormsg);
}
}
}

View File

@ -3,11 +3,11 @@ 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.rmi.ServerException;
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;
@ -22,6 +22,7 @@ import jakarta.ws.rs.NotFoundException;
/**
* Utility class to query EndPoints and search for AccessPoints from IS
*
* @author Alfredo Oliviero (ISTI - CNR)
*/
@ -35,6 +36,7 @@ public class InfrastrctureServiceClient {
* @param category
* @param accessPointName
* @param is_root_service
*
* @return the list of EndPoints matching the parameters
* @throws Exception
*/
@ -46,7 +48,7 @@ public class InfrastrctureServiceClient {
if (resource_name != null) {
query.addCondition("$resource/Profile/Name/text() eq '" + resource_name + "'");
}
if (category != null){
if (category != null) {
query.addCondition("$resource/Profile/Category/text() eq '" + category + "'");
}
DiscoveryClient<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
@ -77,19 +79,18 @@ public class InfrastrctureServiceClient {
}
/**
* obatains the list of AccessPoints matching the parameters
*
* @param resource_name
* @param category
* @param accessPointName
* @param endPointName
* @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 {
String endPointName, boolean is_root_service) {
List<ServiceEndpoint> resources = getEndopintsFromIS(resource_name, category, is_root_service);
@ -100,11 +101,11 @@ public class InfrastrctureServiceClient {
}
List<ServiceEndpoint.AccessPoint> response = new ArrayList<ServiceEndpoint.AccessPoint>();
resources.forEach(res -> {
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));
if (endPointName == null) {
access_points_res = access_points_res.filter(ap -> ap.name().equals(endPointName));
}
access_points_res.forEach(a -> response.add(a));
@ -113,21 +114,23 @@ public class InfrastrctureServiceClient {
}
/**
* obatains the list of AccessPoints matching the parameters, and returns the first one
* obatains the list of AccessPoints matching the parameters, and returns the
* first one
*
* @param resource_name
* @param category
* @param accessPointName
* @param entryPointName
* @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 {
public static ServiceEndpoint.AccessPoint getFirstAccessPointFromIS(String resource_name, String category,
String entryPointName, boolean root_service) {
List<ServiceEndpoint.AccessPoint> access_points = getAccessPointsFromIS(resource_name, category, accessPointName, root_service);
List<ServiceEndpoint.AccessPoint> access_points = getAccessPointsFromIS(resource_name, category, entryPointName,
root_service);
if (access_points.size() == 0) {
logger.error("Unable to retrieve service endpoint " + accessPointName);
logger.error("Unable to retrieve service endpoint " + entryPointName);
return null;
}
@ -135,38 +138,40 @@ public class InfrastrctureServiceClient {
}
/**
/**
* 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 {
*
* @param resourceName
* @param category
* @param accessPointName
* @param is_root_service
* @return
* @throws Exception
*/
public static IsServerConfig serviceConfigFromIS(String resourceName, String category, String endPointName,
boolean is_root_service)
throws NotFoundException, ServerException {
logger.info("Starting creating service credentials");
ServiceEndpoint.AccessPoint accessPoint = InfrastrctureServiceClient.getAccessPointFromIS(resourceName,
category, accessPointName, is_root_service);
logger.info("Starting creating service credentials");
ServiceEndpoint.AccessPoint accessPoint = InfrastrctureServiceClient.getFirstAccessPointFromIS(resourceName,
category, endPointName, is_root_service);
if (accessPoint == null) {
String error_log = "Unable to retrieve service endpoint " + accessPointName;
if (accessPoint == null) {
String error_log = "Unable to retrieve service endpoint " + endPointName;
logger.error(error_log);
throw new NotFoundException(error_log);
}
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());
try {
IsServerConfig config = new IsServerConfig(accessPoint);
return config;
IsServerConfig config = new IsServerConfig(service_url, name, clientId, clientSecret);
logger.info("Found AccessPoint URL = " + service_url);
return config;
}
} catch (Exception e) {
logger.error("cannot create server config from {}", accessPoint);
e.printStackTrace();
throw new ServerException(e.getMessage());
}
}
}

View File

@ -1,21 +1,35 @@
package org.gcube.service.idm.is;
import java.util.HashMap;
import java.util.Map;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import org.gcube.common.resources.gcore.ServiceEndpoint.Property;
import org.keycloak.OAuth2Constants;
public class IsServerConfig {
private String serverUrl;
private String realm;
private String name;
private String clientId;
private Map<String, String> properties = new HashMap<String, String>();
private String clientSecret;
private String grantType = OAuth2Constants.CLIENT_CREDENTIALS;
public Map<String, String> getProperties(){
return this.properties;
}
public String getServerUrl() {
return serverUrl;
}
public String getRealm() {
return realm;
public String getName() {
return name;
}
public String getClientId() {
@ -30,16 +44,47 @@ public class IsServerConfig {
return grantType;
}
public IsServerConfig(String serverUrl, String realm, String clientId, String clientSecret) {
public boolean hasProperty(String key) {
return this.properties.containsKey(key);
}
public String getProperty(String key) {
return this.properties.get(key);
}
public IsServerConfig(String serverUrl, String name, String clientId, String clientSecret) {
this.serverUrl = serverUrl;
this.realm = realm;
this.name = name;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
public IsServerConfig(String serverUrl, String realm, String clientId, String clientSecret,
public IsServerConfig(String serverUrl, String name, String clientId, String clientSecret,
Map<String, String> properties) {
this(serverUrl, name, clientId, clientSecret);
this.properties = properties;
}
public IsServerConfig(ServiceEndpoint.AccessPoint accessPoint) throws Exception {
this.serverUrl = accessPoint.address();
this.name = accessPoint.name();
this.clientId = accessPoint.username();
this.clientSecret = StringEncrypter.getEncrypter().decrypt(accessPoint.password());
this.properties = new HashMap<String, String>();
for (Property p : accessPoint.properties()) {
String value = p.value();
if (p.isEncrypted()) {
value = StringEncrypter.getEncrypter().decrypt(value);
}
this.properties.put(p.name(), value);
}
}
public IsServerConfig(String serverUrl, String name, String clientId, String clientSecret,
Map<String, String> properties,
String grantType) {
this(serverUrl, realm, clientId, clientSecret);
this(serverUrl, name, clientId, clientSecret, properties);
this.grantType = grantType;
}
}

View File

@ -1,46 +0,0 @@
package org.gcube.service.idm.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

@ -1,10 +1,14 @@
package org.gcube.service.idm.keycloack;
import java.rmi.ServerException;
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.gcube.smartgears.ContextProvider;
import org.gcube.smartgears.context.application.ApplicationContext;
import org.gcube.smartgears.security.SimpleCredentials;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.ClientResource;
@ -13,12 +17,14 @@ 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 String END_POINT_NAME = "d4science";
private final static boolean IS_ROOT_SERVICE = true;
// the singleton obj
@ -46,24 +52,40 @@ public class KkClientFactory {
logger.info("Building KeycloakAPICredentials object");
try {
if (this.config == null) {
this.config = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S,
IS_ROOT_SERVICE);
this.config = fetchIsConfig();
}
// 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());
logger.info("KeycloakAPICredentials object built {} - {}", config.getServerUrl(), config.getName());
}
public void setIsConfig() throws Exception {
this.config = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY, REALM_D4S,
IS_ROOT_SERVICE);
// public IsServerConfig configFromINI() throws NotFoundException, ServerException{
// ApplicationContext appContext = ContextProvider.get();
// SimpleCredentials credentials = (SimpleCredentials)appContext.authorizationProvider().getCredentials();
// IsServerConfig cfg = fetchIsConfig();
// IsServerConfig newConfig = new IsServerConfig(
// cfg.getServerUrl(),
// cfg.getName(),
// credentials.getClientID(), // cfg.getClientId(),
// credentials.getSecret(), // cfg.getClientSecrxet(),
// cfg.getProperties()
// );
// return newConfig;s
// }
public IsServerConfig fetchIsConfig() throws NotFoundException, ServerException {
IsServerConfig cfg = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY, END_POINT_NAME, IS_ROOT_SERVICE);
return cfg;
}
public static String encodeClientIdContext(String context) {
@ -78,12 +100,12 @@ public class KkClientFactory {
Keycloak kclient = KeycloakBuilder.builder()
.serverUrl(config.getServerUrl())
.realm(config.getRealm())
.realm(config.getName())
.grantType(config.getGrantType())
.clientId(config.getClientId()) //
.clientSecret(config.getClientSecret()).build();
return new KeycloackApiClient(kclient, config.getRealm(), context);
return new KeycloackApiClient(kclient, config.getName(), context);
}
public RealmResource getKKRealm() {
@ -119,13 +141,13 @@ public class KkClientFactory {
}
// 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";
// static IsServerConfig getTestConfig() {
// String serverUrl = "https://accounts.dev.d4science.org/auth";
// String realm = "d4science";
// String clientId = "id.d4science.org";
// String clientSecret = "";
return new IsServerConfig(serverUrl, realm, clientId, clientSecret);
}
// return new IsServerConfig(serverUrl, realm, clientId, clientSecret);
// }
}

View File

@ -1,18 +0,0 @@
KKRolesClient.list
KeycloakClientFactory.getKKClientForContext();
String ctx = SecretManagerProvider.get().getContext();
RealmResource realm = getKKRealmForContext();
KeycloackApiClient keycloackApiClient = KeycloakClientFactory.getSingleton().createtKeycloakInstance(ctx).clientIdContext;
List<ClientRepresentation> clients = realm.clients().findByClientId(keycloackApiClient.clientIdContext);
getUserByEmail
RealmResource realm = KeycloakClientFactory.getKKRealmForContext();
String ctx = SecretManagerProvider.get().getContext();
KeycloakClientFactory factory = KeycloakClientFactory.getSingleton()
new KeycloakClientFactory()
lookupPropertiesFromIs();

View File

@ -1,89 +1,85 @@
package org.gcube.service.idm.liferay;
import org.gcube.common.encryption.encrypter.StringEncrypter;
import org.gcube.common.resources.gcore.ServiceEndpoint;
import java.rmi.ServerException;
import org.gcube.service.idm.is.InfrastrctureServiceClient;
import org.gcube.service.idm.is.IsServerConfig;
import org.gcube.vomanagement.usermanagement.impl.ws.LiferayWSUserManager;
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);
private static final Logger logger = LoggerFactory.getLogger(LoggerFactory.class);
// Service endpoint properties
private final static String RUNTIME_RESOURCE_NAME = "D4Science Infrastructure Gateway";
// 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 String END_POINT_NAME = "JSONWSUser";
private final static boolean IS_ROOT_SERVICE = true;
private static LiferayClientFactory singleton = new LiferayClientFactory();
LiferayWSUserManager client = null;
/**
* 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 LiferayWSUserManager createtLiferayClientInstance(IsServerConfig config)
throws NotFoundException, ServerException {
String host = config.getServerUrl();
String schema = config.getProperty("schema");
String user = config.getProperty("username");
String password = config.getProperty("password");
Integer port = Integer.valueOf(config.getProperty("port"));
LiferayWSUserManager client = null;
try {
client = new LiferayWSUserManager(user, password, host, schema, port);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new ServerException("cannot create Liferay client");
}
if (client == null) {
throw new ServerException("cannot create Liferay client");
}
logger.info("Liferay object built {} - {}", config.getServerUrl(), config.getName());
return client;
}
public IsServerConfig getConfig() throws NotFoundException, ServerException {
if (this.config == null) {
this.config = fetchIsConfig();
}
return this.config;
}
public LiferayWSUserManager getClient() throws NotFoundException, ServerException {
if (this.client == null) {
IsServerConfig configuration = this.getConfig();
this.client = createtLiferayClientInstance(configuration);
}
return this.client;
}
private static LiferayClientFactory singleton = new LiferayClientFactory();
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();
public IsServerConfig fetchIsConfig() throws NotFoundException, ServerException {
IsServerConfig cfg = InfrastrctureServiceClient.serviceConfigFromIS(RUNTIME_RESOURCE_NAME, CATEGORY,
END_POINT_NAME,
IS_ROOT_SERVICE);
} catch (Exception e) {
logger.error("error obtaining Liferay configuration from IS {} ", e);
}
logger.info("Liferay object built {} - {}", config.getServerUrl(), config.getRealm() );
return cfg;
}
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

@ -0,0 +1,56 @@
package org.gcube.service.idm.mappers;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import org.gcube.service.rest.ResponseBean;
/**
* @author Alfredo Oliviero (ISTI - CNR)
*/
@Provider
public class ForbiddenExceptionMapper implements ExceptionMapper<ForbiddenException> {
@Override
public Response toResponse(ForbiddenException exception) {
Status status = Status.INTERNAL_SERVER_ERROR;
String exceptionMessage = exception.getMessage();
ResponseBean responseBean = null;
try {
if (exception.getCause() != null) {
exceptionMessage = exception.getCause().getMessage();
}
} catch (Exception e) {
exceptionMessage = exception.getMessage();
}
MediaType mediaType = MediaType.TEXT_PLAIN_TYPE;
if (WebApplicationException.class.isAssignableFrom(exception.getClass())) {
Response gotResponse = ((WebApplicationException) exception).getResponse();
Object entity = gotResponse.getEntity();
if (entity != null && ResponseBean.class.isAssignableFrom(entity.getClass())) {
responseBean = (ResponseBean) entity;
}
status = Status.fromStatusCode(gotResponse.getStatusInfo().getStatusCode());
}
if (responseBean == null) {
responseBean = new ResponseBean();
}
responseBean.setSuccess(false);
responseBean.setMessage(exceptionMessage);
// responseBean.set
return Response.status(status).entity(responseBean).type(mediaType).build();
}
}

View File

@ -0,0 +1,55 @@
package org.gcube.service.idm.mappers;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import org.gcube.service.rest.ResponseBean;
/**
* @author Luca Frosini (ISTI - CNR)
*/
@Provider
public class IDMExceptionMapper implements ExceptionMapper<Exception> {
@Override
public Response toResponse(Exception exception) {
Status status = Status.INTERNAL_SERVER_ERROR;
String exceptionMessage = exception.getMessage();
ResponseBean responseBean = null;
try {
if (exception.getCause() != null) {
exceptionMessage = exception.getCause().getMessage();
}
} catch (Exception e) {
exceptionMessage = exception.getMessage();
}
MediaType mediaType = MediaType.TEXT_PLAIN_TYPE;
if (WebApplicationException.class.isAssignableFrom(exception.getClass())) {
Response gotResponse = ((WebApplicationException) exception).getResponse();
Object entity = gotResponse.getEntity();
if (entity != null && ResponseBean.class.isAssignableFrom(entity.getClass())) {
responseBean = (ResponseBean) entity;
}
status = Status.fromStatusCode(gotResponse.getStatusInfo().getStatusCode());
}
if (responseBean == null) {
responseBean = new ResponseBean();
}
responseBean.setSuccess(false);
responseBean.setMessage(exceptionMessage);
// responseBean.set
return Response.status(status).entity(responseBean).type(mediaType).build();
}
}

View File

@ -0,0 +1,185 @@
package org.gcube.service.idm.rest;
import java.util.List;
import jakarta.ws.rs.NotFoundException;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.AdminKeycloakController;
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.ResponseBeanMap;
import org.gcube.smartgears.annotations.ManagedBy;
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;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Response;
@ManagedBy(IdMManager.class)
@Path("clients")
public class ClientsAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ClientsAPI.class);
@GET
@Path("/{name}")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response clientByName(
@PathParam("name") String client_name) {
ResponseBeanMap responseBean = new ResponseBeanMap();
try {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
List<ClientRepresentation> clients = realm.clients().findByClientId(client_name);
if (clients.size() == 0) {
throw new NotFoundException();
}
String id = clients.get(0).getId();
ClientResource clientResource = realm.clients().get(id);
ClientRepresentation client = clientResource.toRepresentation();
UserRepresentation service_account_user = clientResource.getServiceAccountUser();
responseBean.putResult("client", client);
responseBean.putResult("service_account_user", service_account_user);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
public class ClientFromTemplateParams {
String client_name;
String client_id;
String context;
}
@POST
@Path("/fromTemplate/{name}")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response createClientFromTemplate(
@PathParam("name") String template_name,
ClientFromTemplateParams params
) {
ResponseBeanMap responseBean = new ResponseBeanMap();
try {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
List<ClientRepresentation> clients = realm.clients().findByClientId(template_name);
if (clients.size() == 0) {
throw new NotFoundException();
}
String id = clients.get(0).getId();
ClientResource clientResource = realm.clients().get(id);
ClientRepresentation client = clientResource.toRepresentation();
UserRepresentation template_account_user = clientResource.getServiceAccountUser();
client.setId(params.client_id);
client.setName(params.client_name);
responseBean.putResult("client", client);
responseBean.putResult("service_account_user", template_account_user);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
@POST
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response createClientFromTemplate(ClientRepresentation client) {
logger.info("received client {}", client);
ResponseBeanMap responseBean = new ResponseBeanMap();
try {
logger.info("received client {}", client);
ClientRepresentation newClient = AdminKeycloakController.createClient(client);
responseBean.putResult("input", client);
responseBean.putResult("created", newClient);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
@POST
@Path("/")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response createClient(ClientRepresentation client) {
ResponseBeanMap responseBean = new ResponseBeanMap();
try {
logger.info("received client {}", client);
ClientRepresentation newClient = AdminKeycloakController.createClient(client);
responseBean.putResult("input", client);
responseBean.putResult("created", newClient);
responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
}

View File

@ -0,0 +1,92 @@
package org.gcube.service.idm.rest;
import java.util.HashMap;
import java.util.Map;
import jakarta.ws.rs.core.MediaType;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.controller.AuthController;
import org.gcube.service.idm.controller.JWTController;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ErrorMessages;
import org.gcube.service.rest.ResponseBean;
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.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
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;
@Path("jwt")
public class JwtAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JwtAPI.class);
@GET
@Path("/decode")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getDecodedJwtToken(
@QueryParam("token") String token) {
// Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> decoded = JWTController.decodeJwtToken(token);
responseBean.setResult(decoded);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
@GET
@Path("/auth")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
@StatusCodes({
@ResponseCode(code = 200, condition = "The user's email is reported in the 'result' field of the returned object"),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getDecodedJwtAuth() {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
String token = AuthController.getAccessToken();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> response = new HashMap<String, Object>();
response.put("auth_token", JWTController.decodeJwtToken(token));
// response.put("authorizations", authorizations);
responseBean.setResult(response);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
}

View File

@ -1,127 +0,0 @@
package org.gcube.service.idm.rest;
import java.util.HashMap;
import java.util.Map;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
import org.slf4j.LoggerFactory;
import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
@Path("jwt")
public class JwtService {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JwtService.class);
public static Map<String, Object> decodeJwtToken(String token)
throws JsonMappingException, JsonProcessingException {
DecodedJWT decodedJWT = JWT.decode(token);
String headerJson = ContextSerializator.decodeBase64String(decodedJWT.getHeader());
String payloadJson = ContextSerializator.decodeBase64String(decodedJWT.getPayload());
// String signatureJson =
// ContextSerializator.decodeBase64String(decodedJWT.getSignature());
Map<String, Object> decoded = new HashMap<String, Object>();
decoded.put("jwt_token", token);
decoded.put("token", decodedJWT.getToken());
decoded.put("header", ContextSerializator.jsonStringToHasmap(headerJson));
decoded.put("payload", ContextSerializator.jsonStringToHasmap(payloadJson));
// decoded.put("signature",
// ContextSerializator.jsonStringToHasmap(signatureJson));
decoded.put("decodedJWT", decodedJWT);
return decoded;
}
@GET
@Path("/decode")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getDecodedJwtToken(
@QueryParam("token") String token) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> decoded = decodeJwtToken(token);
responseBean.setResult(decoded);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JWTDecodeException e) {
e.printStackTrace();
logger.error("error decoding the token", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
catch (Exception e) {
logger.error("error processing the decoding request", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
}
@GET
@Path("/auth")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getDecodedJwtAuth() {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
Map<String, String> authorizations = SecretManagerProvider.get().getHTTPAuthorizationHeaders();
String token = authorizations.get("Authorization").replace("Bearer", "").trim();
try {
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Map<String, Object> response = new HashMap<String, Object>();
response.put("auth_token", decodeJwtToken(token));
// response.put("authorizations", authorizations);
responseBean.setResult(response);
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JWTDecodeException e) {
e.printStackTrace();
logger.error("error decoding the token", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
catch (Exception e) {
e.printStackTrace();
logger.error("error processing the decoding request", e);
responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
return Response.status(status).entity(responseBean).build();
}
}
}

View File

@ -3,7 +3,7 @@ package org.gcube.service.idm.rest;
import java.util.List;
import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.KKRolesClient;
import org.gcube.service.idm.controller.KKRolesController;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean;
@ -21,13 +21,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
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")
@ -42,7 +42,6 @@ public class RolesAPI {
@QueryParam("max") Integer maxResults,
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) {
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
@ -63,12 +62,7 @@ public class RolesAPI {
} 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();
throw new InternalServerErrorException(e);
}
}
@ -77,11 +71,10 @@ public class RolesAPI {
@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);
RoleRepresentation role = KKRolesController.getRoleByName(role_name);
responseBean.setResult(role);
responseBean.setSuccess(true);
@ -93,13 +86,7 @@ public class RolesAPI {
} 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();
throw new InternalServerErrorException(e);
}
}
@ -110,7 +97,6 @@ public class RolesAPI {
@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);
@ -135,14 +121,7 @@ public class RolesAPI {
} 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();
throw new InternalServerErrorException(e);
}
}
}

View File

@ -1,54 +1,163 @@
package org.gcube.service.idm.rest;
import java.lang.reflect.MalformedParametersException;
import java.util.HashMap;
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.controller.AuthController;
import org.gcube.service.idm.controller.JWTController;
import org.gcube.service.idm.controller.KCUserController;
import org.gcube.service.idm.controller.LiferayProfileClient;
import org.gcube.service.idm.keycloack.KkClientFactory;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ErrorMessages;
import org.gcube.service.rest.ResponseBean;
import org.gcube.service.rest.ResponseBeanMap;
import org.gcube.service.rest.ResponseBeanPaginated;
import org.gcube.smartgears.annotations.ManagedBy;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
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.ws.rs.BadRequestException;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
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);
public class UserAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserAPI.class);
// /me for full personal daata
@GET
@Path("/{username}")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"),
@ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED),
@ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getUser(
@PathParam("username") String username) {
ResponseBeanMap responseBean = new ResponseBeanMap();
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
boolean is_me = false;
if (username.equals("me")) {
// if (owner.isApplication()) {
// // only users can use "me"
// throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
// }
is_me = true;
username = owner.getId();
}
if (!AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES)
&& !AuthController.userIsMe(username, owner)) {
// the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
}
UserRepresentation user = KCUserController.getUserByUsername(username);
try {
if (is_me) {
String token = AuthController.getAccessToken();
responseBean.putResult("owner", owner);
responseBean.putResult("verify", JWTController.decodeJwtToken(token));
}
UserResource userResource = KCUserController.getUserResourceByUsername(username);
MappingsRepresentation roles = userResource.roles().getAll();
responseBean.putResult("roles", roles );
List<GroupRepresentation> groups = userResource.groups();
responseBean.putResult("groups", groups );
HashMap<String, Object> groupRolesRealm = new HashMap<String, Object>();
HashMap<String, Object> groupRolesClients = new HashMap<String, Object>();
responseBean.putResult("groupRolesRealm", groupRolesRealm );
responseBean.putResult("groupRolesClients", groupRolesClients );
for (GroupRepresentation g : groups) {
groupRolesClients.put(g.getId(), g.getClientRoles());
}
groups.get(0).getClientRoles();
responseBean.putResult("user", user);
if (! owner.isApplication()) {
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
responseBean.putResult("profile", profile);
// throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
}
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
@GET
@Path("/me/owner")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getCurrentUsers() {
Status status = Status.OK;
@StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"),
@ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED),
@ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getCurrentUser() {
ResponseBean responseBean = new ResponseBean();
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
// if (owner.isApplication()) {
// // responseBean.setResult(null);
// // return Response.status(404).entity(responseBean).build();
// throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
// }
try {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
// UserResource user = KKUserClient.getUserById();
// UserResource user = KCUserController.getUserById();
responseBean.setResult(owner);
responseBean.setSuccess(true);
@ -59,52 +168,55 @@ public class UserApi {
} 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();
throw new InternalServerErrorException(e);
}
}
// @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" })
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"),
@ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED),
@ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getUserParameter(
@PathParam("username") String username,
@PathParam("parameter") String parameter) {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
if (username.equals("me")) {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
username = owner.getId();
}
try {
if (!AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES)
&& !AuthController.userIsMe(username, owner)) {
// the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
}
UserRepresentation user = KKUserClient.getUserByUsername(username);
try {
if (parameter.equals("profile")) {
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
responseBean.setResult(profile);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
}
UserRepresentation user = KCUserController.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());
@ -129,27 +241,20 @@ public class UserApi {
else if (parameter.equals("attributes"))
responseBean.setResult(user.getAttributes());
else if (parameter.equals("organization"))
responseBean.setResult(user.getAttributes().get("organizations"));
else if (parameter.equals("user")){
responseBean.setResult(user);
}
else
throw new MalformedParametersException("unknow parameter " + parameter);
throw new BadRequestException("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();
throw new InternalServerErrorException(e);
}
}
@ -167,8 +272,6 @@ public class UserApi {
@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);
@ -182,6 +285,11 @@ public class UserApi {
List<UserRepresentation> users = realm.users().search(username, firstName, lastName, email, emailVerified,
idpAlias, idpUserId, firstResult, maxResults, enabled, briefRepresentation);
if (!AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES)) {
// the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
}
responseBean.setResult(users);
responseBean.setSuccess(true);
@ -192,42 +300,8 @@ public class UserApi {
} 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();
throw new InternalServerErrorException(e);
}
}
@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

@ -9,13 +9,14 @@ 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.ErrorMessages;
import org.gcube.service.idm.controller.AuthController;
import org.gcube.service.idm.controller.KCUserController;
import org.gcube.service.idm.controller.LiferayProfileClient;
import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ErrorMessages;
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;
@ -29,6 +30,7 @@ import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import jakarta.validation.ValidationException;
import jakarta.validation.constraints.NotNull;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.ForbiddenException;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
@ -38,7 +40,7 @@ import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
@ManagedBy(IdMManager.class)
@Path("social/users")
@Path("2/users")
// @ResourceGroup("Users APIs")
// @ResourceLabel("Greetings APIs")
// @RequestHeaders({
@ -48,27 +50,207 @@ import jakarta.ws.rs.core.Response.Status;
public class UsersSocialAPI {
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",
// "Quota-Manager");
/**
* 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 = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response readCustomAttr(
@QueryParam("username") String username,
@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();
if (username == null || username.equals("me")) {
if (owner.isApplication()) {
logger.warn("Trying to access users method via a token different than USER is not allowed");
// only users can use "me"
throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
}
username = owner.getId();
}
if (!AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES) && !username.equals(owner.getId())) {
// the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
}
UserRepresentation user = KCUserController.getUserByUsername(username);
Map<String, List<String>> attributes = user.getAttributes();
if (attributes.containsKey(attributeKey)) {
responseBean.setResult(attributes.get(attributeKey));
responseBean.setSuccess(true);
} else {
responseBean.setSuccess(false);
String msg = String.format("Unable to retrieve attribute %s for user %s", attributeKey, user.getUsername());
responseBean.setMessage(msg);
logger.error(msg);
status = Status.NOT_FOUND;
}
return Response.status(status).entity(responseBean).build();
}
/**
* Read the user's fullname. The user is the one owning the token
*
* @return the user's fullname
*/
@GET
@Path("get-fullname")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "The user's fullname is reported in the 'result' field of the returned object"),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
})
public Response getUserFullname() {
ResponseBean responseBean = new ResponseBean();
Status status = Status.OK;
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
String username = owner.getId();
String fullName = null;
if (owner.isApplication()) {
logger.warn("Trying to access users method via a token different than USER is not allowed");
// only users can use "me"
throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
}
try {
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
fullName = profile.getFullname();
logger.info("Found fullname " + fullName + " for user " + username);
responseBean.setResult(fullName);
responseBean.setSuccess(true);
} catch (Exception e) {
logger.error("Unable to retrieve attribute for user.", e);
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
/**
* Read the user's email address. The user is the one owning the token
*
* @return rhe user's email address
*/
@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 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;
try {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
String username = owner.getId();
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
responseBean.setResult(profile);
responseBean.setResult(profile);
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-usernames-by-role")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getUsernamesByRole(
@QueryParam("role-name") String roleName,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
@QueryParam("first") Integer first,
@QueryParam("max") Integer max,
@QueryParam("firstResult") Integer firstResult,
@QueryParam("maxResults") Integer maxResults) {
if (first > 0) {
firstResult = first;
}
if (max > 0) {
maxResults = first;
}
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
responseBean = new ResponseBean();
List<String> usernames = new ArrayList<String>();
try {
List<UserRepresentation> users = KKUserClient.searchUsersByRole(roleName, firstResult, maxResults);
List<UserRepresentation> users = KCUserController.searchUsersByRole(roleName, firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
@ -103,18 +285,27 @@ public class UsersSocialAPI {
@QueryParam("enabled") Boolean enabled,
@QueryParam("briefRepresentation") @DefaultValue("true") Boolean briefRepresentation,
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults) {
@QueryParam("first") Integer first,
@QueryParam("max") Integer max,
@QueryParam("firstResult") Integer firstResult,
@QueryParam("maxResults") Integer maxResults) {
if (first > 0) {
firstResult = first;
}
if (max > 0) {
maxResults = first;
}
Status status = Status.OK;
ResponseBean responseBean;
if (firstResult != null || maxResults != null ) {
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try {
UsersResource users_resource = KKUserClient.users();
UsersResource users_resource = KCUserController.users();
List<UserRepresentation> users = users_resource.search(emailVerified, firstResult, maxResults, enabled,
briefRepresentation);
@ -139,148 +330,6 @@ public class UsersSocialAPI {
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" })
@ -297,7 +346,7 @@ public class UsersSocialAPI {
List<String> usernames = new ArrayList<String>();
try {
List<UserRepresentation> users = KKUserClient.users(firstResult, maxResults);
List<UserRepresentation> users = KCUserController.users(firstResult, maxResults);
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
@ -331,7 +380,7 @@ public class UsersSocialAPI {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
UserRepresentation user = KKUserClient.getUserByUsername(username);
UserRepresentation user = KCUserController.getUserByUsername(username);
boolean user_exists = user != null;
responseBean.setResult(user_exists);
@ -354,10 +403,36 @@ public class UsersSocialAPI {
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();
// }
@GET
@Path("/get-oauth-profile")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response getCurrentOAuthProfile() {
Status status = Status.OK;
ResponseBean responseBean = new ResponseBean();
try {
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
UserRepresentation user = KCUserController.getUserByUsername(owner.getId());
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(ErrorMessages.CANNOT_RETRIEVE_PROFILE);
// responseBean.setMessage(e.getMessage());
status = Status.INTERNAL_SERVER_ERROR;
}
return Response.status(status).entity(responseBean).build();
}
}

View File

@ -1,15 +1,15 @@
package org.gcube.service.idm.rest.test;
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.smartgears.utils.InnerMethodName;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* @author Lucio Lelii (ISTI - CNR)
* @author Alfredo Oliviero (ISTI - CNR)

View File

@ -0,0 +1,32 @@
package org.gcube.service.rest;
public class ErrorMessages
{
public static final String ERROR_IN_API_RESULT = "The error is reported into the 'message' field of the returned object";
public static final String INVALID_ATTRIBUTE = "Such an attribute doesn't exist";
public static final String NOT_USER_TOKEN_CONTEXT_USED = "User's information can only be retrieved through a user token (not qualified)";
public static final String USER_NOT_AUTHORIZED_PRIVATE = "User is not authorized to access private data";
public static final String CANNOT_RETRIEVE_PROFILE = "Unable to retrieve user profile";
//
// 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 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,76 @@
package org.gcube.service.rest;
import java.util.HashMap;
import java.util.Map;
/**
* Response bean
*
*/
public class ResponseBeanMap extends ResponseBean {
private static final long serialVersionUID = -2725238162673879658L;
/**
* The result of the request: true if it succeeded, false otherwise
*/
protected boolean success;
/**
* An error message if something wrong happened, null/empty otherwise
*/
protected String message;
/**
* The result object of the request
*/
protected Map<String, Object>result = new HashMap<String, Object>();
public ResponseBeanMap() {
super();
}
/**
* @param success
* @param message
* @param result
*/
public ResponseBeanMap(boolean success, String message, Map<String, Object> mapResults) {
super();
this.success = success;
this.message = message;
this.result = mapResults;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<String, Object> getResult() {
return result;
}
public void setResult(Map<String, Object> mapResults) {
this.result = mapResults;
}
public void putResult(String key, Object res){
this.result.put(key, res);
}
@Override
public String toString() {
return "ResponseBean [success=" + success
+ ", message=" + message + ", result=" + result + "]";
}
}

45
todo.md
View File

@ -1,26 +1,27 @@
# 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
*
# MASSI
* API REST social
* [ ] stesso path (con 2/ davanti)
* [ ] verificare di accettare esattamente stessi parametri
* [ ]usare stesso bean (senza limit e max )
* nel token abbiamo i ruoli realm globali. al momento smartgear li ignora, bisogna implementare logica di accesso basata su quei ruoli. verificare se smartgear li legge, in caso contrario fare una chiamata di appoggio che li ottiene dal token, versione futura si appoggerà su smartgear
* "realm_access":
{
"roles": [
"offline_access",
"uma_authorization",
"service-endpoint-key"
]
},
* [ ] implementare client (rif. gcat-client)
* [ ] verificare controllo diritti
* [ ] mettere su openstack