500 lines
19 KiB
Java
500 lines
19 KiB
Java
package org.gcube.service.idm.rest;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
import org.gcube.service.idm.IdMManager;
|
|
import org.gcube.service.idm.controller.AdminKeycloakController;
|
|
import org.gcube.service.idm.controller.AuthController;
|
|
import org.gcube.service.idm.controller.KCClientsController;
|
|
import org.gcube.service.idm.controller.KCGroupsController;
|
|
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.serializers.IdmObjectSerializator;
|
|
import org.gcube.service.utils.ErrorMessages;
|
|
import org.gcube.service.utils.beans.ResponseBean;
|
|
import org.gcube.service.utils.beans.ResponseBeanMap;
|
|
import org.gcube.smartgears.annotations.ManagedBy;
|
|
import org.keycloak.admin.client.resource.ClientResource;
|
|
import org.keycloak.admin.client.resource.GroupResource;
|
|
import org.keycloak.admin.client.resource.RealmResource;
|
|
import org.keycloak.admin.client.resource.RoleResource;
|
|
import org.keycloak.admin.client.resource.RolesResource;
|
|
import org.keycloak.representations.idm.ClientRepresentation;
|
|
import org.keycloak.representations.idm.GroupRepresentation;
|
|
import org.keycloak.representations.idm.RoleRepresentation;
|
|
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.RequestHeader;
|
|
import com.webcohesion.enunciate.metadata.rs.RequestHeaders;
|
|
|
|
import jakarta.ws.rs.DefaultValue;
|
|
import jakarta.ws.rs.GET;
|
|
import jakarta.ws.rs.InternalServerErrorException;
|
|
import jakarta.ws.rs.NotFoundException;
|
|
import jakarta.ws.rs.POST;
|
|
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.Response;
|
|
|
|
@ManagedBy(IdMManager.class)
|
|
@RequestHeaders({
|
|
@RequestHeader(name = "Authorization", description = "Bearer token, see https://dev.d4science.org/how-to-access-resources"),
|
|
@RequestHeader(name = "Content-Type", description = "application/json")
|
|
})
|
|
@Path("clients")
|
|
public class ClientsAPI {
|
|
|
|
/**
|
|
* returns the list of members of the client with the given role
|
|
*
|
|
* default client is the current client, optional clientId to show a different
|
|
* one
|
|
*
|
|
* default showed role is "Member"
|
|
*
|
|
* output format can be customized using format_users
|
|
*
|
|
* @param client_id optional clientId (aka encoded context). if absent,
|
|
* uses
|
|
* current context
|
|
*
|
|
* @param format_users response format for users. use "none" for skip
|
|
*
|
|
* @param role role to inspect, default Member.
|
|
*
|
|
* @param firstResult pagination offset
|
|
* @param maxResults maximum results size
|
|
*/
|
|
|
|
@GET
|
|
@Path("members")
|
|
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
|
|
public Response clientMembers(
|
|
@QueryParam("first") @DefaultValue("0") int firstResult,
|
|
@QueryParam("max") @DefaultValue("100") int maxResults,
|
|
@QueryParam("format_users") @DefaultValue("username") KCUserController.REPR format_users,
|
|
@QueryParam("role") @DefaultValue("Member") String role_name,
|
|
@QueryParam("client_id") String clientId) {
|
|
ResponseBean responseBean = new ResponseBean();
|
|
|
|
if (clientId != null) {
|
|
AuthController.checkIsRealmAdmin(ErrorMessages.RESERVED_PARAMETER + "client_id");
|
|
}
|
|
|
|
// RealmResource realmResource = KkClientFactory.getSingleton().getKKRealm();
|
|
// ClientResource clientResource = null;
|
|
|
|
// // select the client by name, or current client if client_name parameter is
|
|
// // null;
|
|
// if (clientId == null) {
|
|
// clientResource = KkClientFactory.getSingleton().getKKClient();
|
|
// } else {
|
|
|
|
// List<ClientRepresentation> clients =
|
|
// realmResource.clients().findByClientId(clientId);
|
|
|
|
// if (clients.size() == 0) {
|
|
// throw new NotFoundException();
|
|
// }
|
|
// String id = clients.get(0).getId();
|
|
|
|
// clientResource = realmResource.clients().get(id);
|
|
// }
|
|
|
|
// RolesResource roles_resource = clientResource.roles();
|
|
// RoleResource role_resource = roles_resource.get(role_name);
|
|
// List<UserRepresentation> user_members =
|
|
// role_resource.getUserMembers(firstResult, maxResults);
|
|
|
|
List<UserRepresentation> user_members = KCClientsController.getContextUsersByRole(clientId, role_name,
|
|
firstResult, maxResults);
|
|
|
|
Object result = KCUserController.formatList(user_members, format_users);
|
|
responseBean.setResult(result);
|
|
|
|
try {
|
|
responseBean.setSuccess(true);
|
|
ObjectMapper objectMapper = IdmObjectSerializator.getSerializer();
|
|
|
|
String jsonData = objectMapper.writeValueAsString(responseBean);
|
|
return Response.ok(jsonData).build();
|
|
|
|
} catch (
|
|
|
|
JsonProcessingException e) {
|
|
e.printStackTrace();
|
|
throw new InternalServerErrorException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* returns the list of users of the client
|
|
* users list is a subset of members list, it's obtained from the group named as
|
|
* the context
|
|
*
|
|
* default client is the current client, optional clientId to show a different
|
|
* one
|
|
*
|
|
* output format can be customized using format_users
|
|
*
|
|
* @param client_id optional clientId (aka encoded context). if absent,
|
|
* uses
|
|
* current context
|
|
*
|
|
* @param format_users response format for users. use "none" for skip
|
|
*
|
|
* @param role list of roles to inspect, default Member. can use
|
|
* multiple times. use '__all__' to get all roles in the
|
|
* client
|
|
* @param firstResult pagination offset
|
|
* @param maxResults maximum results size
|
|
*/
|
|
|
|
@GET
|
|
@Path("users")
|
|
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
|
|
public Response clientUsers(
|
|
@QueryParam("first") @DefaultValue("0") int firstResult,
|
|
@QueryParam("max") @DefaultValue("100") int maxResults,
|
|
|
|
@QueryParam("format_users") @DefaultValue("username") KCUserController.REPR format_users,
|
|
@QueryParam("client_id") String clientId) {
|
|
ResponseBean responseBean = new ResponseBean();
|
|
|
|
if (clientId != null) {
|
|
AuthController.checkIsRealmAdmin(ErrorMessages.RESERVED_PARAMETER + "client_id");
|
|
}
|
|
|
|
List<UserRepresentation> user_members = KCClientsController.getMemberGroupUsers(clientId, firstResult,
|
|
maxResults);
|
|
Object result = KCUserController.formatList(user_members, format_users);
|
|
responseBean.setResult(result);
|
|
|
|
try {
|
|
responseBean.setSuccess(true);
|
|
ObjectMapper objectMapper = IdmObjectSerializator.getSerializer();
|
|
|
|
String jsonData = objectMapper.writeValueAsString(responseBean);
|
|
return Response.ok(jsonData).build();
|
|
|
|
} catch (
|
|
|
|
JsonProcessingException e) {
|
|
e.printStackTrace();
|
|
throw new InternalServerErrorException(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* returns an inspection of the client, showing roles and related members
|
|
* default client is the current client, optional clientId to show a different
|
|
* one
|
|
*
|
|
* output format can be customized using format_client, format_users,
|
|
* format_roles, format_groups
|
|
*
|
|
* default showed role is "Member", use role="__all__" to show all roles
|
|
*
|
|
* @param client_id optional clientId (aka encoded context). if absent,
|
|
* uses
|
|
* current context
|
|
*
|
|
* @param format_users response format for users. use "none" for skip
|
|
* @param format_roles response format for users. use "none" for skip
|
|
* @param format_client response format for client. use "none" for skip
|
|
* @param format_groups response format for group. use "none" for skip
|
|
*
|
|
* @param role list of roles to inspect, default Member. can use
|
|
* multiple times. use '__all__' to get all roles in the
|
|
* client
|
|
*/
|
|
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(ClientsAPI.class);
|
|
|
|
@GET
|
|
@Path("info")
|
|
@Produces({ "application/json;charset=UTF-8", "application/vnd.api+json" })
|
|
public Response client(
|
|
@QueryParam("format_client") @DefaultValue("compact") KCClientsController.REPR format_client,
|
|
@QueryParam("format_users") @DefaultValue("username") KCUserController.REPR format_users,
|
|
@QueryParam("format_roles") @DefaultValue("compact") KCRolesController.REPR format_roles,
|
|
@QueryParam("format_groups") @DefaultValue("name") KCGroupsController.REPR format_group,
|
|
@QueryParam("role") @DefaultValue("Member") final List<String> roles,
|
|
@QueryParam("client_id") String clientId) {
|
|
ResponseBeanMap responseBean = new ResponseBeanMap();
|
|
|
|
if (clientId != null) {
|
|
AuthController.checkIsRealmAdmin(ErrorMessages.RESERVED_PARAMETER + "client_id");
|
|
}
|
|
|
|
// String role_name = "Member";
|
|
|
|
boolean show_groups = !format_group.equals(KCGroupsController.REPR.none);
|
|
boolean show_client = !format_client.equals(KCClientsController.REPR.none);
|
|
boolean show_users = !format_users.equals(KCUserController.REPR.none);
|
|
boolean show_roles = !format_roles.equals(KCRolesController.REPR.none);
|
|
|
|
RealmResource realmResource = KkClientFactory.getSingleton().getKKRealm();
|
|
ClientResource clientResource = null;
|
|
ClientRepresentation client = null;
|
|
|
|
// select the client by name, or current client if client_name parameter is
|
|
// null;
|
|
if (clientId == null) {
|
|
clientResource = KkClientFactory.getSingleton().getKKClient();
|
|
client = clientResource.toRepresentation();
|
|
} else {
|
|
|
|
List<ClientRepresentation> clients = realmResource.clients().findByClientId(clientId);
|
|
|
|
if (clients.size() == 0) {
|
|
throw new NotFoundException();
|
|
}
|
|
String id = clients.get(0).getId();
|
|
|
|
clientResource = realmResource.clients().get(id);
|
|
client = clientResource.toRepresentation();
|
|
}
|
|
|
|
if (show_client)
|
|
responseBean.putResult("client", KCClientsController.formatRepr(client,
|
|
format_client));
|
|
|
|
if (format_client.equals(KCClientsController.REPR.full)) {
|
|
UserRepresentation service_account_user = clientResource.getServiceAccountUser();
|
|
responseBean.putResult("service_account_user",
|
|
KCUserController.formatRepr(service_account_user, format_users));
|
|
}
|
|
|
|
HashMap<String, Object> roles_dict = new HashMap<String, Object>();
|
|
responseBean.putResult("roles", roles_dict);
|
|
|
|
RolesResource roles_resource = clientResource.roles();
|
|
|
|
List<RoleRepresentation> roles_list = null;
|
|
if (roles == null || roles.isEmpty() || roles.contains("__all__")) {
|
|
roles_list = roles_resource.list();
|
|
} else {
|
|
roles_list = new ArrayList<RoleRepresentation>();
|
|
for (String role_name : roles) {
|
|
try {
|
|
RoleResource role_resource = roles_resource.get(role_name);
|
|
RoleRepresentation role_repr = role_resource.toRepresentation();
|
|
roles_list.add(role_repr);
|
|
} catch (Exception e) {
|
|
roles_dict.put(role_name, null);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (RoleRepresentation role_repr : roles_list) {
|
|
String role_name = role_repr.getName();
|
|
RoleResource role_resource = roles_resource.get(role_name);
|
|
|
|
HashMap<String, Object> role_dict = new HashMap<String, Object>();
|
|
roles_dict.put(role_name, role_dict);
|
|
|
|
if (show_roles) {
|
|
role_dict.put("role", KCRolesController.formatRepr(role_repr, format_roles));
|
|
}
|
|
|
|
if (show_users) {
|
|
List<UserRepresentation> user_members = role_resource.getUserMembers();
|
|
role_dict.put("members",
|
|
KCUserController.formatList(user_members, format_users));
|
|
}
|
|
|
|
if (show_groups) {
|
|
HashMap<String, HashMap<String, Object>> groups_hash = new HashMap<String, HashMap<String, Object>>();
|
|
|
|
role_dict.put("groups", groups_hash);
|
|
Set<GroupRepresentation> groups_members = clientResource.roles().get(role_name).getRoleGroupMembers();
|
|
|
|
for (GroupRepresentation g_repr : groups_members) {
|
|
|
|
HashMap<String, Object> group_dict = new HashMap<String, Object>();
|
|
groups_hash.put(g_repr.getPath(), group_dict);
|
|
group_dict.put("group", KCGroupsController.formatRepr(g_repr, format_group));
|
|
if (show_users) {
|
|
|
|
GroupResource g = realmResource.groups().group(g_repr.getId());
|
|
List<UserRepresentation> members = g.members();
|
|
group_dict.put("members",
|
|
KCUserController.formatList(members, format_users));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
try {
|
|
responseBean.setSuccess(true);
|
|
ObjectMapper objectMapper = IdmObjectSerializator.getSerializer();
|
|
|
|
String jsonData = objectMapper.writeValueAsString(responseBean);
|
|
return Response.ok(jsonData).build();
|
|
|
|
} catch (
|
|
|
|
JsonProcessingException e) {
|
|
e.printStackTrace();
|
|
throw new InternalServerErrorException(e);
|
|
}
|
|
}
|
|
|
|
// cannot pass the client name in the path. %2f blocked by tomcat security
|
|
// @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);
|
|
// Set<GroupRepresentation> members =
|
|
// clientResource.roles().get("Member").getRoleGroupMembers();
|
|
// responseBean.putResult("members", members);
|
|
|
|
// responseBean.setSuccess(true);
|
|
|
|
// ObjectMapper objectMapper = IdmObjectSerializator.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 = IdmObjectSerializator.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 = IdmObjectSerializator.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 = IdmObjectSerializator.getSerializer();
|
|
|
|
String jsonData = objectMapper.writeValueAsString(responseBean);
|
|
return Response.ok(jsonData).build();
|
|
|
|
} catch (JsonProcessingException e) {
|
|
e.printStackTrace();
|
|
throw new InternalServerErrorException(e);
|
|
}
|
|
}
|
|
|
|
}
|