package org.ovirt.engine.api.restapi.resource.aaa; import static org.ovirt.engine.api.utils.ReflectionHelper.assignChildModel; import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.Collection; import java.util.List; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.api.model.BaseResource; import org.ovirt.engine.api.model.User; import org.ovirt.engine.api.model.Users; import org.ovirt.engine.api.resource.aaa.UserResource; import org.ovirt.engine.api.resource.aaa.UsersResource; import org.ovirt.engine.api.restapi.resource.AbstractBackendCollectionResource; import org.ovirt.engine.api.restapi.resource.ResourceConstants; import org.ovirt.engine.api.restapi.util.QueryHelper; import org.ovirt.engine.api.restapi.utils.DirectoryEntryIdUtils; import org.ovirt.engine.api.restapi.utils.aaa.AuthzUtils; import org.ovirt.engine.core.aaa.DirectoryUser; import org.ovirt.engine.core.common.action.AddUserParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.aaa.DbUser; import org.ovirt.engine.core.common.interfaces.SearchType; import org.ovirt.engine.core.common.queries.DirectoryIdQueryParameters; import org.ovirt.engine.core.common.queries.GetDirectoryUserByPrincipalParameters; import org.ovirt.engine.core.common.queries.IdQueryParameters; import org.ovirt.engine.core.common.queries.VdcQueryParametersBase; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; /** * This resource corresponds to users that have been looked up in some directory * accessible to the engine and then added to the engine database. Users can * be added and removed from the collection, and this will add or remove them * from the database (not from the underlying directory). */ public class BackendUsersResource extends AbstractBackendCollectionResource<User, DbUser> implements UsersResource { private static final String USERS_SEARCH_PATTERN = "usrname != \"\""; private static final String AND_SEARCH_PATTERN = " and "; private BackendDomainResource parent; public BackendUsersResource() { super(User.class, DbUser.class); } public BackendUsersResource(String id, BackendDomainResource parent) { super(User.class, DbUser.class); this.parent = parent; } public BackendUsersResource(Class<User> class1, Class<DbUser> class2) { super(class1, class2); } /** * This method calculates the search pattern that will be used to perform * the search of database users during the execution of the {@code list} * operation. */ private String getSearchPattern() { String user_defined_pattern = QueryHelper.getConstraint(httpHeaders, uriInfo, "", modelType); return user_defined_pattern.equals("Users : ") ? user_defined_pattern + USERS_SEARCH_PATTERN : user_defined_pattern + AND_SEARCH_PATTERN + USERS_SEARCH_PATTERN; } protected String getAuthzProviderName(User user, Collection<String> authzProvidersNames) { if (user.isSetDomain() && user.getDomain().isSetName()) { return user.getDomain().getName(); } else if (user.isSetDomain() && user.getDomain().isSetId()) { for (String domain : authzProvidersNames) { Guid domainId = asGuid(domain.getBytes(StandardCharsets.UTF_8), true); if (domainId.toString().equals(user.getDomain().getId())) { return domain; } } throw new WebFaultException(null, "Domain: '" + user.getDomain().getId().toString() + "' does not exist.", Response.Status.BAD_REQUEST); } return AuthzUtils.getAuthzNameFromEntityName(user.getUserName(), authzProvidersNames); } /** * This method calculates the search pattern used to search for the * directory user that will be added to the database when performing the * {@code add} operation. * * @param username the name of the user that will be searched in the * directory * @param domain the name of the directory where the search will be * performed */ private String getDirectoryUserSearchPattern(String username, String namespace, String domain) { String constraint = QueryHelper.getConstraint(httpHeaders, uriInfo, DbUser.class, false); final StringBuilder sb = new StringBuilder(128); sb.append(MessageFormat.format(ResourceConstants.AAA_PRINCIPALS_SEARCH_TEMPLATE, parent!=null? parent.getDirectory().getName() : domain, namespace != null ? namespace : "")); sb.append(StringUtils.isEmpty(constraint) ? "username=" + username : constraint); return sb.toString(); } protected Users mapDbUserCollection(List<DbUser> entities) { Users collection = new Users(); for (DbUser entity : entities) { User user = map(entity); user = populate(user, entity); user = addLinks(user, BaseResource.class); collection.getUsers().add(user); } return collection; } @Override protected User addParents(User user) { if(parent!=null){ assignChildModel(user, User.class).setId(parent.get().getId()); } return user; } public UserResource getUserResource(String id) { return inject(new BackendUserResource(id, this)); } public Users list() { if (isFiltered()) { return mapDbUserCollection(getBackendCollection(VdcQueryType.GetAllDbUsers, new VdcQueryParametersBase(), SearchType.DBUser)); } else { return mapDbUserCollection(getBackendCollection(SearchType.DBUser, getSearchPattern())); } } @Override public Response add(User user) { validateParameters(user, "userName"); List<String> authzProvidersNames = getBackendCollection( String.class, VdcQueryType.GetDomainList, new VdcQueryParametersBase()); if (AuthzUtils.getAuthzNameFromEntityName(user.getUserName(), authzProvidersNames) == null) {// user-name may contain the domain (e.g: oliel@xxx.yyy) validateParameters(user, "domain.id|name"); } String domain = getAuthzProviderName(user, authzProvidersNames); DirectoryUser directoryUser = findDirectoryUser(domain, user); if (directoryUser == null) { return Response.status(Status.BAD_REQUEST) .entity("No such user: " + user.getUserName() + " in domain " + domain) .build(); } AddUserParameters parameters = new AddUserParameters(new DbUser(directoryUser)); QueryIdResolver<Guid> resolver = new QueryIdResolver<>(VdcQueryType.GetDbUserByUserId, IdQueryParameters.class); return performCreate(VdcActionType.AddUser, parameters, resolver, BaseResource.class); } /** * Find the directory user that corresponds to the given model. * * @param directoryName the name of the directory where to perform the search * @param user the user model * @return the requested directory group or {@code null} if no such group exists */ private DirectoryUser findDirectoryUser(String directoryName, User user) { DirectoryUser result = null; String namespace = user.getNamespace(); if (user.isSetDomainEntryId()) { result = getUserById(directoryName, namespace, user.getDomainEntryId()); } else if (user.isSetId()) { result = getUserById(directoryName, namespace, user.getId()); } else if (user.isSetPrincipal()) { result = getEntity(DirectoryUser.class, VdcQueryType.GetDirectoryUserByPrincipal, new GetDirectoryUserByPrincipalParameters(directoryName, user.getPrincipal()), user.getPrincipal()); } else if (user.isSetUserName()) { result = getEntity( DirectoryUser.class, SearchType.DirectoryUser, getDirectoryUserSearchPattern( AuthzUtils.getEntityNameWithoutAuthz(user.getUserName(), directoryName), user.getNamespace(), directoryName) ); } return result; } private DirectoryUser getUserById(String directoryName, String namespace, String userId) { DirectoryUser result; try { userId = DirectoryEntryIdUtils.decode(userId); } catch (IllegalArgumentException exception) { return null; } result = getEntity( DirectoryUser.class, VdcQueryType.GetDirectoryUserById, new DirectoryIdQueryParameters(directoryName, namespace, userId), userId, true); return result; } }