revieved implementation, javadoc and enunciate documentation

This commit is contained in:
Alfredo Oliviero 2024-04-17 20:53:55 +02:00
parent cd3875360c
commit ae67b28d16
9 changed files with 446 additions and 150 deletions

View File

@ -6,8 +6,8 @@
<groupId>org.gcube.idm</groupId> <groupId>org.gcube.idm</groupId>
<artifactId>idm</artifactId> <artifactId>idm</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<name>Identity Manager Smargears</name> <name>Identity Manager (IDM) Service</name>
<description>Identity Manager Smargears Service</description> <description>Identity Manager (IDM) Service - Smartgears</description>
<packaging>war</packaging> <packaging>war</packaging>
<parent> <parent>
@ -28,7 +28,7 @@
<!-- bind jackson version to avoid inconsistences with keycloak dependencies --> <!-- bind jackson version to avoid inconsistences with keycloak dependencies -->
<jackson.version>2.15.3</jackson.version> <jackson.version>2.15.3</jackson.version>
<enunciate.version>2.17.1</enunciate.version> <enunciate.version>2.16.1</enunciate.version>
<keycloak.client.version>21.1.2</keycloak.client.version> <keycloak.client.version>21.1.2</keycloak.client.version>
</properties> </properties>
@ -125,6 +125,8 @@ solution: bind version, or exclude them in usermanagement-core
<version>4.4.13</version> <version>4.4.13</version>
</dependency> </dependency>
--> -->
<!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-admin-client -->
<dependency> <dependency>
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId> <artifactId>keycloak-admin-client</artifactId>

View File

@ -24,6 +24,7 @@ import jakarta.ws.rs.WebApplicationException;
public class AdminKeycloakController { public class AdminKeycloakController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AdminKeycloakController.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(AdminKeycloakController.class);
// TODO: Using Keycloak Admin Client to create user with roles (Realm and Client level)
// https://gist.github.com/thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b // https://gist.github.com/thomasdarimont/c4e739c5a319cf78a4cff3b87173a84b
public static UserRepresentation createUser(String username, String email, String password, String firstName, public static UserRepresentation createUser(String username, String email, String password, String firstName,
String lastName, Map<String, List<String>> attributes, List<String> roles) throws WebApplicationException { String lastName, Map<String, List<String>> attributes, List<String> roles) throws WebApplicationException {
@ -51,10 +52,9 @@ public class AdminKeycloakController {
// throws exception if creationResponse is failed // throws exception if creationResponse is failed
try { try {
javax.ws.rs.core.Response creationResponse = usersRessource.create(newUser); newUserId = CreatedResponseUtil.getCreatedId(usersRessource.create(newUser));
newUserId = CreatedResponseUtil.getCreatedId(creationResponse);
} catch (javax.ws.rs.WebApplicationException e) { } catch (WebApplicationException e) {
logger.error("error creating user {} - {}", newUser, e.getMessage()); logger.error("error creating user {} - {}", newUser, e.getMessage());
e.printStackTrace(); e.printStackTrace();
@ -193,10 +193,9 @@ public class AdminKeycloakController {
// throws exception if creationResponse is failed // throws exception if creationResponse is failed
try { try {
javax.ws.rs.core.Response creationResponse = clientsResource.create(newClient); newClientId = CreatedResponseUtil.getCreatedId(clientsResource.create(newClient));
newClientId = CreatedResponseUtil.getCreatedId(creationResponse);
} catch (javax.ws.rs.WebApplicationException e) { } catch (WebApplicationException e) {
logger.error("error creating client {} - {}", newClient, e.getMessage()); logger.error("error creating client {} - {}", newClient, e.getMessage());
e.printStackTrace(); e.printStackTrace();

View File

@ -8,9 +8,9 @@ import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider; import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.common.security.secrets.Secret; import org.gcube.common.security.secrets.Secret;
public class AuthController { public class AuthController {
public final static String IDM_SERVICE_READ = "idm-service-read"; public final static String IDM_SERVICE_READ = "idm-service-read";
public final static String IDM_SERVICE_ADMIN = "idm-service-admin"; public final static String IDM_SERVICE_ADMIN = "idm-service-admin";

View File

@ -1,5 +1,6 @@
package org.gcube.service.idm.controller; package org.gcube.service.idm.controller;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.gcube.service.idm.keycloack.KkClientFactory; import org.gcube.service.idm.keycloack.KkClientFactory;
@ -11,9 +12,35 @@ import org.slf4j.LoggerFactory;
import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
public class KKRolesController { public class KCRolesController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KKRolesController.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KCRolesController.class);
public enum REPRESENTATION {
full, compact, name, id
}
public static Object formatListRoles(List<RoleRepresentation> roles, KCRolesController.REPRESENTATION format) {
if (format.equals(KCRolesController.REPRESENTATION.id)) {
List<String> ids = new ArrayList<String>();
if (roles != null) {
for (RoleRepresentation role : roles) {
ids.add(role.getId());
}
}
return ids;
} else if (format.equals(KCRolesController.REPRESENTATION.name)) {
List<String> names = new ArrayList<String>();
if (roles != null) {
for (RoleRepresentation role : roles) {
names.add(role.getName());
}
}
return names;
} else
return roles;
}
public static List<RoleRepresentation> getRoles() { public static List<RoleRepresentation> getRoles() {
logger.info("Searching users for context"); logger.info("Searching users for context");
ClientResource client = KkClientFactory.getSingleton().getKKClient(); ClientResource client = KkClientFactory.getSingleton().getKKClient();

View File

@ -1,6 +1,9 @@
package org.gcube.service.idm.controller; package org.gcube.service.idm.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.gcube.common.security.providers.SecretManagerProvider; import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.service.idm.keycloack.KeycloackApiClient; import org.gcube.service.idm.keycloack.KeycloackApiClient;
@ -19,12 +22,61 @@ import jakarta.ws.rs.NotFoundException;
public class KCUserController { public class KCUserController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KCUserController.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(KCUserController.class);
public enum REPRESENTATION {
full, compact, username, email, id, email_username, fullname
}
public static UsersResource users() { public static UsersResource users() {
RealmResource realm = KkClientFactory.getSingleton().getKKRealm(); RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
UsersResource users = realm.users(); UsersResource users = realm.users();
return users; return users;
} }
public static Object formatListUsers(List<UserRepresentation> users, KCUserController.REPRESENTATION format){
if (format.equals(KCUserController.REPRESENTATION.username)) {
List<String> usernames = new ArrayList<String>();
if (users != null) {
for (UserRepresentation user : users) {
usernames.add(user.getUsername());
}
}
return usernames;
} else if (format.equals(KCUserController.REPRESENTATION.email)) {
List<String> emails = new ArrayList<String>();
if (users != null) {
for (UserRepresentation user : users) {
emails.add(user.getEmail());
}
}
return emails;
} else if (format.equals(KCUserController.REPRESENTATION.id)) {
List<String> ids = new ArrayList<String>();
if (users != null) {
for (UserRepresentation user : users) {
ids.add(user.getId());
}
}
return ids;
}else if (format.equals(KCUserController.REPRESENTATION.email_username)) {
Map<String, String> usernamesAndFullnames = new HashMap<String, String>();
users.forEach(user -> usernamesAndFullnames.put(user.getUsername(), user.getEmail()));
return usernamesAndFullnames;
}else if (format.equals(KCUserController.REPRESENTATION.fullname)) {
List<String> fullnames = new ArrayList<String>();
if (users != null) {
for (UserRepresentation user : users) {
fullnames.add(user.getFirstName() + " " + user.getLastName());
}
}
return fullnames;
} else
return users;
}
/** /**
* Search for users based on the given filters. * Search for users based on the given filters.
* *

View File

@ -1,9 +1,11 @@
package org.gcube.service.idm.rest; package org.gcube.service.idm.rest;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.gcube.service.idm.IdMManager; import org.gcube.service.idm.IdMManager;
import org.gcube.service.idm.controller.KKRolesController; import org.gcube.service.idm.controller.KCRolesController;
import org.gcube.service.idm.controller.KCUserController;
import org.gcube.service.idm.keycloack.KkClientFactory; import org.gcube.service.idm.keycloack.KkClientFactory;
import org.gcube.service.idm.serializers.ContextSerializator; import org.gcube.service.idm.serializers.ContextSerializator;
import org.gcube.service.rest.ResponseBean; import org.gcube.service.rest.ResponseBean;
@ -34,25 +36,30 @@ import jakarta.ws.rs.core.Response;
public class RolesAPI { 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);
/**
* Returns roles in context
*
* @param format roles response format
* @param firstResult pagination offset
* @param maxResults maximum results size
* @param search filter by name
*/
@GET @GET
@Path("/") @Path("/")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response search(@QueryParam("search") @DefaultValue("") String search, public Response search(@QueryParam("search") @DefaultValue("") String search,
@QueryParam("first") Integer firstResult, @QueryParam("first") @DefaultValue("0") int firstResult,
@QueryParam("max") Integer maxResults, @QueryParam("max") @DefaultValue("100") int maxResults,
@QueryParam("briefRepresentation") @DefaultValue("true") boolean briefRepresentation) { @QueryParam("format") @DefaultValue("name") KCRolesController.REPRESENTATION format) {
ResponseBean responseBean = new ResponseBeanPaginated(firstResult, maxResults);
Boolean briefRepresentation = !KCRolesController.REPRESENTATION.full.equals(format);
ResponseBean responseBean;
if (firstResult != null || maxResults != null) {
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try { try {
ClientResource client = KkClientFactory.getSingleton().getKKClient(); ClientResource client = KkClientFactory.getSingleton().getKKClient();
List<RoleRepresentation> roles = client.roles().list(search, firstResult, maxResults, briefRepresentation); List<RoleRepresentation> roles = client.roles().list(search, firstResult, maxResults, briefRepresentation);
responseBean.setResult(roles); responseBean.setResult(KCRolesController.formatListRoles(roles, format));
responseBean.setSuccess(true); responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer(); ObjectMapper objectMapper = ContextSerializator.getSerializer();
@ -66,15 +73,21 @@ public class RolesAPI {
} }
} }
/**
* Returns role by name
*
* @path role_name the role
* 'email' and 'username' must match exactly. default true
*/
@GET @GET
@Path("/{name}") @Path("/{role_name}")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" }) @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response role( public Response role(
@PathParam("name") String role_name) { @PathParam("role_name") String role_name) {
ResponseBean responseBean = new ResponseBean(); ResponseBean responseBean = new ResponseBean();
try { try {
RoleRepresentation role = KKRolesController.getRoleByName(role_name); RoleRepresentation role = KCRolesController.getRoleByName(role_name);
responseBean.setResult(role); responseBean.setResult(role);
responseBean.setSuccess(true); responseBean.setSuccess(true);
@ -90,19 +103,24 @@ public class RolesAPI {
} }
} }
/**
* Returns the list of users with role in the context
*
* @param format users response format
* @param role_name the role
* @param firstResult pagination offset
* @param maxResults maximum results size
*/
@GET @GET
@Path("/{role_name}/users") @Path("/{role_name}/users")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" }) @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
public Response usersForRole( public Response usersForRole(
@PathParam("role_name") String role_name, @PathParam("role_name") String role_name,
@QueryParam("first") Integer firstResult, @QueryParam("first") @DefaultValue("0") int firstResult,
@QueryParam("max") Integer maxResults) { @QueryParam("max") @DefaultValue("100") int maxResults,
ResponseBean responseBean; @QueryParam("format") @DefaultValue("username") KCUserController.REPRESENTATION format) {
if (firstResult != null || maxResults != null) { ResponseBean responseBean = new ResponseBeanPaginated(firstResult, maxResults);
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try { try {
ClientResource client = KkClientFactory.getSingleton().getKKClient(); ClientResource client = KkClientFactory.getSingleton().getKKClient();
@ -111,7 +129,7 @@ public class RolesAPI {
List<UserRepresentation> users = r.getUserMembers(firstResult, maxResults); List<UserRepresentation> users = r.getUserMembers(firstResult, maxResults);
responseBean.setResult(users); responseBean.setResult(KCUserController.formatListUsers(users, format));
responseBean.setSuccess(true); responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer(); ObjectMapper objectMapper = ContextSerializator.getSerializer();

View File

@ -1,7 +1,9 @@
package org.gcube.service.idm.rest; package org.gcube.service.idm.rest;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.gcube.common.security.Owner; import org.gcube.common.security.Owner;
import org.gcube.common.security.providers.SecretManagerProvider; import org.gcube.common.security.providers.SecretManagerProvider;
@ -43,87 +45,148 @@ import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
/**
* <p>
* The REST API to interact with the keycloak users
* </p>
*
* <p>
* "Member" users can only invoke metods on his own user (/me)
* </p>
*
* <p>
* Users with "idm-service-read" or "idm-service-admin" role can invoke metods
* on all the users
* </p>
*
* @author Alfredo Oliviero (ISTI - CNR)
*/
@ManagedBy(IdMManager.class) @ManagedBy(IdMManager.class)
@Path("users") @Path("users")
public class UserAPI { public class UserAPI {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserAPI.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UserAPI.class);
// /me for full personal daata /**
* Returns infos about the authenticated user
*
* <ul>
* <li>owner: the authenticated user</li>
* <li>profile: the profile of the user in the Liferay CMS (only if the user is
* not a service)</li>
* <li>user: the user representation from the authentication service</li>
* </uL>
*
* if the optional parameter inspect is passed as true, returns additional
* values:
* <ul>
* <li>verify: the result of introspection of the auth token on the
* authentication service</li>
* <li>roles: the authenticated user</li>
* <li>groups: the authenticated user</li>
* <li>groupRolesRealm: ...</li>
* <li>groupRolesClients: ...</li>
* </ul>
*
* @param inspect adds additional inspection values to the result
* @returns infos about the authenticated user
*
*/
@GET
@Path("/me")
@Produces(MediaType.APPLICATION_JSON)
@StatusCodes({
@ResponseCode(code = 200, condition = "current user informations"),
@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 getMe(
@QueryParam("inspect") @DefaultValue("false") Boolean inspect) {
logger.info("/users/me");
ResponseBean responseBean = new ResponseBean();
ObjectMapper objectMapper = ContextSerializator.getSerializer();
Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
String username = owner.getId();
// if (owner.isApplication()) {
// // only users can use "me"
// throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
// }
Map<String, Object> result = getUserData(username, !owner.isApplication(), inspect);
responseBean.setResult(result);
result.put("owner", owner);
try {
if (inspect) {
String token = AuthController.getAccessToken();
result.put("verify", JWTController.decodeJwtToken(token));
}
responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build();
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new InternalServerErrorException(e);
}
}
/**
* Returns informations about the user received as parameter
*
* Only users with "idm-service-read" or "idm-service-admin" role can invoke
* this method
*
* <ul>
* <li>profile: the profile of the user in the Liferay CMS (only if the user is
* not a service)</li>
* <li>user: the user representation from the authentication service</li>
* </uL>
*
* if the optional parameter inspect is passed as true, returns additional
* values:
* <ul>
* <li>roles: the authenticated user</li>
* <li>groups: the authenticated user</li>
* <li>groupRolesRealm: ...</li>
* <li>groupRolesClients: ...</li>
* </ul>
*
* @param username the username of the user
* @param inspect adds additional inspection values to the result
* @returns infos about the user
*/
@GET @GET
@Path("/{username}") @Path("/{username}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"), @ResponseCode(code = 200, condition = "user informations"),
@ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED), @ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED),
@ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE), @ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT) @ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
}) })
public Response getUser( public Response getUser(
@PathParam("username") String username) { @PathParam("username") String username,
@QueryParam("inspect") @DefaultValue("false") Boolean inspect) {
ResponseBeanMap responseBean = new ResponseBeanMap(); ResponseBeanMap responseBean = new ResponseBeanMap();
ObjectMapper objectMapper = ContextSerializator.getSerializer(); ObjectMapper objectMapper = ContextSerializator.getSerializer();
Secret secret = SecretManagerProvider.get(); if (!AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES)) {
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 // the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE); throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
} }
UserRepresentation user = KCUserController.getUserByUsername(username); Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner();
try { try {
Map<String, Object> result = getUserData(username, !owner.isApplication(), inspect);
if (is_me) { responseBean.setResult(result);
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); responseBean.setSuccess(true);
String jsonData = objectMapper.writeValueAsString(responseBean); String jsonData = objectMapper.writeValueAsString(responseBean);
@ -134,11 +197,49 @@ public class UserAPI {
} }
} }
protected Map<String, Object> getUserData(String username, Boolean getProfile, Boolean isInspect) {
Map<String, Object> result = new HashMap<>();
UserRepresentation user = KCUserController.getUserByUsername(username);
result.put("user", user);
if (getProfile) {
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
result.put("profile", profile);
// throw new ForbiddenException(ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED);
}
if (isInspect) {
UserResource userResource = KCUserController.getUserResourceByUsername(username);
MappingsRepresentation roles = userResource.roles().getAll();
result.put("roles", roles);
List<GroupRepresentation> groups = userResource.groups();
result.put("groups", groups);
HashMap<String, Object> groupRolesRealm = new HashMap<String, Object>();
HashMap<String, Object> groupRolesClients = new HashMap<String, Object>();
result.put("groupRolesRealm", groupRolesRealm);
result.put("groupRolesClients", groupRolesClients);
for (GroupRepresentation g : groups) {
groupRolesClients.put(g.getId(), g.getClientRoles());
}
groups.get(0).getClientRoles();
}
return result;
}
/**
* @returns the owner object of the authenticated user
*/
@GET @GET
@Path("/me/owner") @Path("/me/owner")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" }) @Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
@StatusCodes({ @StatusCodes({
@ResponseCode(code = 200, condition = "decode the token"), @ResponseCode(code = 200, condition = "infos about the owner of the auth token"),
@ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED), @ResponseCode(code = 403, condition = ErrorMessages.NOT_USER_TOKEN_CONTEXT_USED),
@ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE), @ResponseCode(code = 404, condition = ErrorMessages.INVALID_ATTRIBUTE),
@ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT) @ResponseCode(code = 500, condition = ErrorMessages.ERROR_IN_API_RESULT)
@ -149,12 +250,6 @@ public class UserAPI {
Secret secret = SecretManagerProvider.get(); Secret secret = SecretManagerProvider.get();
Owner owner = secret.getOwner(); 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 { try {
// UserResource user = KCUserController.getUserById(); // UserResource user = KCUserController.getUserById();
@ -172,6 +267,88 @@ public class UserAPI {
} }
} }
/**
* @returns the result of introspection of the auth token on the
* authentication service
*/
@GET
@Path("/me/verify")
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+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 getInrospectioCurrenttUser() {
ResponseBean responseBean = new ResponseBean();
try {
String token = AuthController.getAccessToken();
responseBean.setResult(JWTController.decodeJwtToken(token));
// UserResource user = KCUserController.getUserById();
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);
}
}
/**
* Returns informations about the user received as parameter (can be also me)
*
* Normal member users can use only "me" or his username as parameter
*
* Users with "idm-service-read" or "idm-service-admin" role can invoke
* this method with any username
*
* accepted parameters are:
*
* <ul>
* <li>profile: returns the profile of the user in the Liferay CMS (only if the
* user is
* not a service)</li>
* <li>email: returns the email of the user from the authentication service</li>
*
* <li>user: the user representation from the authentication service</li>
* </uL>
*
* if the optional parameter inspect is passed as true, returns additional
* values:
* <ul>
* <li>roles_realm: roles in realm for the user from the authentication
* service</li>
* <li>roles_clients: roles in clients for the user from the authentication
* service</li>
* <li>groups: id of the user from the authentication service</li>
* <li>username: username of the user from the authentication service</li>
* <li>name: Fullname of the user from the authentication service</li>
* <li>attributes: attributes of the user from the authentication service</li>
* <li>user: full user from the authentication service</li>
* <li>profile: profile of the user from the Liferay CMS service</li>
* </ul>
*
* @param username the username of the user
* @param parameter the parameter to obtain. accepts profile, email,
* roles_realm, roles_clients, groups, id, username , name,
* attributes, user
* @param inspect adds additional inspection values to the result
* @returns infos about the user
*/
public enum USER_DETAILS {
profile, email, roles_realm, roles_clients,
groups, id, username, name, attributes, user
}
@GET @GET
@Path("/{username}/{parameter}") @Path("/{username}/{parameter}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -183,7 +360,7 @@ public class UserAPI {
}) })
public Response getUserParameter( public Response getUserParameter(
@PathParam("username") String username, @PathParam("username") String username,
@PathParam("parameter") String parameter) { @PathParam("parameter") USER_DETAILS parameter) {
ResponseBean responseBean = new ResponseBean(); ResponseBean responseBean = new ResponseBean();
ObjectMapper objectMapper = ContextSerializator.getSerializer(); ObjectMapper objectMapper = ContextSerializator.getSerializer();
@ -192,7 +369,7 @@ public class UserAPI {
Owner owner = secret.getOwner(); Owner owner = secret.getOwner();
if (username.equals("me")) { if (username.equals("me")) {
username = owner.getId(); username = owner.getId();
} }
@ -203,8 +380,8 @@ public class UserAPI {
} }
try { try {
if (parameter.equals("profile")) { if (parameter.equals(USER_DETAILS.profile)) {
GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username); GCubeUser profile = LiferayProfileClient.getUserProfileByUsername(username);
responseBean.setResult(profile); responseBean.setResult(profile);
@ -214,36 +391,32 @@ public class UserAPI {
UserRepresentation user = KCUserController.getUserByUsername(username); UserRepresentation user = KCUserController.getUserByUsername(username);
if (parameter == null) if (parameter.equals(USER_DETAILS.email))
responseBean.setResult(user);
else if (parameter.equals("email"))
responseBean.setResult(user.getEmail()); responseBean.setResult(user.getEmail());
else if (parameter.equals("roles_realm")) else if (parameter.equals(USER_DETAILS.roles_realm))
responseBean.setResult(user.getRealmRoles()); responseBean.setResult(user.getRealmRoles());
else if (parameter.equals("roles_clients")) else if (parameter.equals(USER_DETAILS.roles_clients))
responseBean.setResult(user.getClientRoles()); responseBean.setResult(user.getClientRoles());
else if (parameter.equals("groups")) else if (parameter.equals(USER_DETAILS.groups))
responseBean.setResult(user.getGroups()); responseBean.setResult(user.getGroups());
else if (parameter.equals("id")) else if (parameter.equals(USER_DETAILS.id))
responseBean.setResult(user.getId()); responseBean.setResult(user.getId());
else if (parameter.equals("username")) else if (parameter.equals(USER_DETAILS.username))
responseBean.setResult(user.getUsername()); responseBean.setResult(user.getUsername());
else if (parameter.equals("name")) else if (parameter.equals(USER_DETAILS.name))
responseBean.setResult(user.getFirstName() + " " + user.getLastName()); responseBean.setResult(user.getFirstName() + " " + user.getLastName());
else if (parameter.equals("attributes")) else if (parameter.equals(USER_DETAILS.attributes))
responseBean.setResult(user.getAttributes()); responseBean.setResult(user.getAttributes());
else if (parameter.equals("user")){ else if (parameter.equals(USER_DETAILS.user) || parameter == null)
responseBean.setResult(user); responseBean.setResult(user);
}
else else
throw new BadRequestException("unknow parameter " + parameter); throw new BadRequestException("unknow parameter " + parameter);
@ -258,43 +431,63 @@ public class UserAPI {
} }
} }
/**
* Returns users, filtered according to query parameters.
*
* @param format response format
* @param exact Boolean which defines whether the params 'last', 'first',
* 'email' and 'username' must match exactly. default true
* @param username A String contained in username, or the complete username,
* if
* param 'exact' is true
* @param firstName A String contained in firstName, or the complete
* firstName,
* if param 'exact' is true
* @param lastName A String contained in firstName, or the complete
* firstName,
* if param 'exact' is true
* @param firstResult pagination offset
* @param maxResults maximum results size
* @param enabled Boolean representing if user is enabled or not
* @param email A String contained in email, or the complete email, if
* param 'exact' is true
*/
@GET @GET
@Path("/search") @Path("/search")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Response search(@QueryParam("username") String username, public Response search(
@QueryParam("firstName") String firstName, @QueryParam("format") @DefaultValue("username") KCUserController.REPRESENTATION format,
@QueryParam("exact") @DefaultValue("true") Boolean exact,
@QueryParam("username") String username,
@QueryParam("firsnName") String firstName,
@QueryParam("lastName") String lastName, @QueryParam("lastName") String lastName,
@QueryParam("email") String email, @QueryParam("email") String email,
@QueryParam("emailVerified") @DefaultValue("true") Boolean emailVerified, @QueryParam("first") @DefaultValue("0") int firstResult,
@QueryParam("idpAlias") String idpAlias, @QueryParam("max") @DefaultValue("100") int maxResults,
@QueryParam("idpUserId") String idpUserId, @QueryParam("enabled") @DefaultValue("true") Boolean enabled) {
@QueryParam("first") Integer firstResult,
@QueryParam("max") Integer maxResults,
@QueryParam("enabled") @DefaultValue("true") Boolean enabled,
@QueryParam("briefRepresentation") @DefaultValue("true") Boolean briefRepresentation) {
ResponseBean responseBean; ResponseBean responseBean;
if (firstResult != null || maxResults != null) { responseBean = new ResponseBeanPaginated(firstResult, maxResults);
responseBean = new ResponseBeanPaginated(firstResult, maxResults);
} else {
responseBean = new ResponseBean();
}
try { try {
if (!format.equals(KCUserController.REPRESENTATION.username)
RealmResource realm = KkClientFactory.getSingleton().getKKRealm(); && !AuthController.checkAnyRole(AuthController.ACCESS_READ_ROLES)) {
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 // the user can see only his profile
throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE); throw new ForbiddenException(ErrorMessages.USER_NOT_AUTHORIZED_PRIVATE);
} }
responseBean.setResult(users); RealmResource realm = KkClientFactory.getSingleton().getKKRealm();
Boolean briefRepresentation = !KCUserController.REPRESENTATION.full.equals(format);
List<UserRepresentation> users = realm.users().search(
username, firstName, lastName, email,
firstResult, maxResults,
enabled, briefRepresentation, exact);
responseBean.setResult(KCUserController.formatListUsers(users, format));
responseBean.setSuccess(true); responseBean.setSuccess(true);
ObjectMapper objectMapper = ContextSerializator.getSerializer(); ObjectMapper objectMapper = ContextSerializator.getSerializer();
String jsonData = objectMapper.writeValueAsString(responseBean); String jsonData = objectMapper.writeValueAsString(responseBean);
return Response.ok(jsonData).build(); return Response.ok(jsonData).build();
@ -303,5 +496,4 @@ public class UserAPI {
throw new InternalServerErrorException(e); throw new InternalServerErrorException(e);
} }
} }
} }

View File

@ -283,7 +283,6 @@ public class UsersSocialAPI {
@QueryParam("emailVerified") Boolean emailVerified, @QueryParam("emailVerified") Boolean emailVerified,
@QueryParam("enabled") Boolean enabled, @QueryParam("enabled") Boolean enabled,
@QueryParam("briefRepresentation") @DefaultValue("true") Boolean briefRepresentation,
@QueryParam("first") Integer first, @QueryParam("first") Integer first,
@QueryParam("max") Integer max, @QueryParam("max") Integer max,
@ -307,19 +306,13 @@ public class UsersSocialAPI {
try { try {
UsersResource users_resource = KCUserController.users(); UsersResource users_resource = KCUserController.users();
List<UserRepresentation> users = users_resource.search(emailVerified, firstResult, maxResults, enabled, List<UserRepresentation> users = users_resource.search(emailVerified, firstResult, maxResults, enabled,
briefRepresentation); true);
if (briefRepresentation) {
Map<String, String> usernamesAndFullnames = new HashMap<String, String>(); Map<String, String> usernamesAndFullnames = new HashMap<String, String>();
users.forEach(user -> usernamesAndFullnames.put(user.getUsername(), user.getEmail())); users.forEach(user -> usernamesAndFullnames.put(user.getUsername(), user.getEmail()));
responseBean.setResult(usernamesAndFullnames); responseBean.setResult(usernamesAndFullnames);
} else {
Map<String, Object> usernamesAndUsers = new HashMap<String, Object>();
users.forEach(user -> usernamesAndUsers.put(user.getUsername(), user));
responseBean.setResult(usernamesAndUsers);
}
responseBean.setSuccess(true); responseBean.setSuccess(true);
} catch (Exception e) { } catch (Exception e) {
logger.error("Unable to retrieve users", e); logger.error("Unable to retrieve users", e);

View File

@ -0,0 +1,13 @@
/**
* <h1>Identity Manager (IDM) Service</h1>
*
* <p>Welcome to Identity Manager Service (aka IDM) API documentation.</p>
*
* <p>
* To get a complete overview of gCat service take a look at
* <a href="../docs/index.html">wiki page</a>.
* </p>
*
*
*/
package org.gcube.service.idm.rest;