org.roda.core.common.UserUtility.java Source code

Java tutorial

Introduction

Here is the source code for org.roda.core.common.UserUtility.java

Source

/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE file at the root of the source
 * tree and available online at
 *
 * https://github.com/keeps/roda
 */
package org.roda.core.common;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import javax.servlet.http.HttpServletRequest;

import org.roda.core.RodaCoreFactory;
import org.roda.core.data.common.RodaConstants;
import org.roda.core.data.exceptions.AuthorizationDeniedException;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.NotFoundException;
import org.roda.core.data.exceptions.RequestNotValidException;
import org.roda.core.data.v2.index.IsIndexed;
import org.roda.core.data.v2.index.select.SelectedItems;
import org.roda.core.data.v2.index.select.SelectedItemsFilter;
import org.roda.core.data.v2.index.select.SelectedItemsList;
import org.roda.core.data.v2.ip.DIPFile;
import org.roda.core.data.v2.ip.IndexedAIP;
import org.roda.core.data.v2.ip.IndexedDIP;
import org.roda.core.data.v2.ip.IndexedFile;
import org.roda.core.data.v2.ip.IndexedRepresentation;
import org.roda.core.data.v2.ip.Permissions.PermissionType;
import org.roda.core.data.v2.ip.metadata.IndexedPreservationEvent;
import org.roda.core.data.v2.user.User;
import org.roda.core.index.IndexService;
import org.roda.core.index.utils.IterableIndexResult;
import org.roda.core.model.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Sets;

public class UserUtility {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserUtility.class);
    public static final String RODA_USER = "RODA_USER";
    private static final String REGISTER_ACTIVE_PROPERTY = "ui.register.active";
    private static final String REGISTER_DEFAULT_GROUPS = "ui.register.defaultGroups";
    private static final String REGISTER_DEFAULT_ROLES = "ui.register.defaultRoles";

    private static LdapUtility ldapUtility;

    /** Private empty constructor */
    private UserUtility() {
        // do nothing
    }

    public static LdapUtility getLdapUtility() {
        return ldapUtility;
    }

    public static void setLdapUtility(LdapUtility utility) {
        ldapUtility = utility;
    }

    public static User getApiUser(final HttpServletRequest request) throws AuthorizationDeniedException {
        return getUser(request, false);
    }

    public static User getUser(final HttpServletRequest request, final boolean returnGuestIfNoUserInSession) {
        User user = (User) request.getSession().getAttribute(RODA_USER);
        if (user == null) {
            user = returnGuestIfNoUserInSession ? getGuest() : null;
        } else {
            if (user.isGuest()) {
                user = getGuest();
            }
        }
        return user;
    }

    public static User getUser(final HttpServletRequest request) {
        return getUser(request, true);
    }

    public static void checkRoles(final User rsu, final List<String> rolesToCheck)
            throws AuthorizationDeniedException {
        // INFO 20170220 nvieira containsAll changed to set intersection (contain at
        // least one role)
        if (!rolesToCheck.isEmpty()
                && Sets.intersection(rsu.getAllRoles(), new HashSet<>(rolesToCheck)).isEmpty()) {
            final List<String> missingRoles = new ArrayList<>(rolesToCheck);
            missingRoles.removeAll(rsu.getAllRoles());

            throw new AuthorizationDeniedException(
                    "The user '" + rsu.getId() + "' does not have all needed permissions", missingRoles);
        }
    }

    public static void checkGroup(final User rsu, final String group) throws AuthorizationDeniedException {
        if (!rsu.getGroups().contains(group)) {
            LOGGER.debug("User '{}' groups: {} vs. group to check: {}", rsu.getId(), rsu.getGroups(), group);
            throw new AuthorizationDeniedException(
                    "The user '" + rsu.getId() + "' does not belong to the group '" + group + "'");
        }
    }

    public static void checkRoles(final User user, final String... rolesToCheck)
            throws AuthorizationDeniedException {
        checkRoles(user, Arrays.asList(rolesToCheck));
    }

    public static void checkRoles(final User user, final Class<?> invokingMethodInnerClass)
            throws AuthorizationDeniedException {
        checkRoles(user, invokingMethodInnerClass, null);
    }

    public static void checkRoles(final User user, final Class<?> invokingMethodInnerClass,
            final Class<?> classToReturn) throws AuthorizationDeniedException {
        final Method method = invokingMethodInnerClass.getEnclosingMethod();
        final String classParam = (classToReturn == null) ? "" : "(" + classToReturn.getSimpleName() + ")";
        final String configKey = String.format("core.roles.%s.%s%s", method.getDeclaringClass().getName(),
                method.getName(), classParam);
        if (RodaCoreFactory.getRodaConfiguration().containsKey(configKey)) {
            LOGGER.trace("Testing if user '{}' has permissions to '{}'", user.getName(), configKey);
            final List<String> roles = RodaCoreFactory.getRodaConfigurationAsList(configKey);
            checkRoles(user, roles);
        } else {
            LOGGER.error(
                    "Unable to determine which roles the user '{}' needs because the config. key '{}' is not defined",
                    user.getName(), configKey);
            throw new AuthorizationDeniedException(
                    "Unable to determine which roles the user needs because the config. key '" + configKey
                            + "' is not defined");
        }
    }

    public static void setUser(final HttpServletRequest request, final User user) {
        request.getSession(true).setAttribute(RODA_USER, user);
    }

    public static void logout(HttpServletRequest servletRequest) {
        servletRequest.getSession().removeAttribute(RODA_USER);

        // CAS specific clean up
        servletRequest.getSession().removeAttribute("edu.yale.its.tp.cas.client.filter.user");
        servletRequest.getSession().removeAttribute("_const_cas_assertion_");
    }

    /**
     * Retrieves guest used
     */
    public static User getGuest() {
        return new User("guest", "guest", true);
    }

    private static boolean iterativeDisjoint(Set<String> set1, Set<String> set2) {
        boolean noCommonElement = true;
        for (String string : set1) {
            if (set2.contains(string)) {
                noCommonElement = false;
                break;
            }
        }
        return noCommonElement;
    }

    /**
     * This method make sure that a normal user can only upload a file to a folder
     * with its own username
     *
     * @param user
     * @param ids
     * @throws AuthorizationDeniedException
     */
    public static void checkTransferredResourceAccess(User user, List<String> ids)
            throws AuthorizationDeniedException {
        // do nothing
    }

    public static boolean isAdministrator(String username) {
        return username.equals(RodaConstants.ADMIN);
    }

    public static boolean isAdministrator(User user) {
        return user.getName().equals(RodaConstants.ADMIN);
    }

    public static void checkAIPPermissions(User user, IndexedAIP aip, PermissionType permissionType)
            throws AuthorizationDeniedException {

        if (isAdministrator(user)) {
            return;
        }

        Set<String> users = aip.getPermissions().getUsers().get(permissionType);
        Set<String> groups = aip.getPermissions().getGroups().get(permissionType);

        LOGGER.debug("Checking if user '{}' has permissions to {} object {} (object read permissions: {} & {})",
                user.getId(), permissionType, aip.getId(), users, groups);

        if (!users.contains(user.getId()) && iterativeDisjoint(groups, user.getGroups())) {
            throw new AuthorizationDeniedException(
                    "The user '" + user.getId() + "' does not have permissions to " + permissionType);
        }
    }

    public static void checkDIPPermissions(User user, IndexedDIP dip, PermissionType permissionType)
            throws AuthorizationDeniedException {

        if (isAdministrator(user)) {
            return;
        }

        Set<String> users = dip.getPermissions().getUsers().get(permissionType);
        Set<String> groups = dip.getPermissions().getGroups().get(permissionType);

        LOGGER.debug("Checking if user '{}' has permissions to {} dip {} (object read permissions: {} & {})",
                user.getId(), permissionType, dip.getId(), users, groups);

        if (!users.contains(user.getId()) && iterativeDisjoint(groups, user.getGroups())) {
            throw new AuthorizationDeniedException(
                    "The user '" + user.getId() + "' does not have permissions to " + permissionType);
        }
    }

    public static <T extends IsIndexed> void checkObjectPermissions(User user, T obj, PermissionType permissionType)
            throws AuthorizationDeniedException {
        if (obj instanceof IndexedAIP) {
            checkAIPPermissions(user, (IndexedAIP) obj, permissionType);
        } else if (obj instanceof IndexedRepresentation) {
            checkRepresentationPermissions(user, (IndexedRepresentation) obj, permissionType);
        } else if (obj instanceof IndexedFile) {
            checkFilePermissions(user, (IndexedFile) obj, permissionType);
        } else if (obj instanceof IndexedDIP) {
            checkDIPPermissions(user, (IndexedDIP) obj, permissionType);
        } else if (obj instanceof DIPFile) {
            checkDIPFilePermissions(user, (DIPFile) obj, permissionType);
        } else if (obj instanceof IndexedPreservationEvent) {
            checkPreservationEventPermissions(user, (IndexedPreservationEvent) obj, permissionType);
        }
    }

    private static <T extends IsIndexed> void checkAIPObjectPermissions(User user, T obj, Function<T, String> toAIP,
            PermissionType permissionType) throws AuthorizationDeniedException {

        if (isAdministrator(user)) {
            return;
        }

        String aipId = toAIP.apply(obj);
        IndexedAIP aip;
        try {
            aip = RodaCoreFactory.getIndexService().retrieve(IndexedAIP.class, aipId,
                    RodaConstants.AIP_PERMISSIONS_FIELDS_TO_RETURN);
        } catch (NotFoundException | GenericException e) {
            throw new AuthorizationDeniedException("Could not check permissions of object " + obj, e);
        }

        Set<String> users = aip.getPermissions().getUsers().get(permissionType);
        Set<String> groups = aip.getPermissions().getGroups().get(permissionType);

        LOGGER.debug("Checking if user '{}' has permissions to {} object {} (object read permissions: {} & {})",
                user.getId(), permissionType, aip.getId(), users, groups);

        if (!users.contains(user.getId()) && iterativeDisjoint(groups, user.getGroups())) {
            throw new AuthorizationDeniedException(
                    "The user '" + user.getId() + "' does not have permissions to " + permissionType);
        }
    }

    private static <T extends IsIndexed> void checkDIPObjectPermissions(User user, T obj, Function<T, String> toDIP,
            PermissionType permissionType) throws AuthorizationDeniedException {

        if (isAdministrator(user)) {
            return;
        }

        String dipId = toDIP.apply(obj);
        IndexedDIP dip;
        try {
            dip = RodaCoreFactory.getIndexService().retrieve(IndexedDIP.class, dipId,
                    RodaConstants.DIP_PERMISSIONS_FIELDS_TO_RETURN);
        } catch (NotFoundException | GenericException e) {
            throw new AuthorizationDeniedException("Could not check permissions of object " + obj, e);
        }

        Set<String> users = dip.getPermissions().getUsers().get(permissionType);
        Set<String> groups = dip.getPermissions().getGroups().get(permissionType);

        LOGGER.debug("Checking if user '{}' has permissions to {} object {} (object read permissions: {} & {})",
                user.getId(), permissionType, dip.getId(), users, groups);

        if (!users.contains(user.getId()) && iterativeDisjoint(groups, user.getGroups())) {
            throw new AuthorizationDeniedException(
                    "The user '" + user.getId() + "' does not have permissions to " + permissionType);
        }
    }

    public static void checkRepresentationPermissions(User user, IndexedRepresentation rep,
            PermissionType permissionType) throws AuthorizationDeniedException {
        checkAIPObjectPermissions(user, rep, r -> r.getAipId(), permissionType);
    }

    public static void checkFilePermissions(User user, IndexedFile file, PermissionType permissionType)
            throws AuthorizationDeniedException {
        checkAIPObjectPermissions(user, file, f -> f.getAipId(), permissionType);
    }

    public static void checkDIPFilePermissions(User user, DIPFile file, PermissionType permissionType)
            throws AuthorizationDeniedException {
        checkDIPObjectPermissions(user, file, f -> f.getDipId(), permissionType);
    }

    public static void checkPreservationEventPermissions(User user, IndexedPreservationEvent event,
            PermissionType permissionType) throws AuthorizationDeniedException {
        checkAIPObjectPermissions(user, event, f -> f.getAipID(), permissionType);
    }

    public static void checkAIPPermissions(User user, SelectedItems<IndexedAIP> selected, PermissionType permission)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {

        if (isAdministrator(user)) {
            return;
        }

        IndexService index = RodaCoreFactory.getIndexService();
        if (selected instanceof SelectedItemsFilter) {
            SelectedItemsFilter<IndexedAIP> selectedItems = (SelectedItemsFilter<IndexedAIP>) selected;
            IterableIndexResult<IndexedAIP> findAll = index.findAll(IndexedAIP.class, selectedItems.getFilter(),
                    RodaConstants.AIP_PERMISSIONS_FIELDS_TO_RETURN);

            for (IndexedAIP aip : findAll) {
                checkAIPPermissions(user, aip, permission);
            }
        } else if (selected instanceof SelectedItemsList) {
            SelectedItemsList<IndexedAIP> selectedItems = (SelectedItemsList<IndexedAIP>) selected;
            List<IndexedAIP> aips = ModelUtils.getIndexedAIPsFromObjectIds(selectedItems);
            for (IndexedAIP aip : aips) {
                checkAIPPermissions(user, aip, permission);
            }
        } else {
            throw new RequestNotValidException(
                    "SelectedItems implementations not supported: " + selected.getClass().getName());
        }
    }

    public static void checkDIPPermissions(User user, SelectedItems<IndexedDIP> selected, PermissionType permission)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {

        if (isAdministrator(user)) {
            return;
        }

        IndexService index = RodaCoreFactory.getIndexService();
        if (selected instanceof SelectedItemsFilter) {
            SelectedItemsFilter<IndexedDIP> selectedItems = (SelectedItemsFilter<IndexedDIP>) selected;
            IterableIndexResult<IndexedDIP> findAll = index.findAll(IndexedDIP.class, selectedItems.getFilter(),
                    RodaConstants.DIP_PERMISSIONS_FIELDS_TO_RETURN);

            for (IndexedDIP dip : findAll) {
                checkDIPPermissions(user, dip, permission);
            }
        } else if (selected instanceof SelectedItemsList) {
            SelectedItemsList<IndexedDIP> selectedItems = (SelectedItemsList<IndexedDIP>) selected;
            List<IndexedDIP> dips = ModelUtils.getIndexedDIPsFromObjectIds(selectedItems);
            for (IndexedDIP dip : dips) {
                checkDIPPermissions(user, dip, permission);
            }
        } else {
            throw new RequestNotValidException(
                    "SelectedItems implementations not supported: " + selected.getClass().getName());
        }
    }

    @SuppressWarnings("unchecked")
    public static <T extends IsIndexed> void checkObjectPermissions(User user, SelectedItems<T> selected,
            PermissionType permissionType)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {
        Class<T> classToReturn = SelectedItemsUtils.parseClass(selected.getSelectedClass());

        if (classToReturn.equals(IndexedAIP.class)) {
            checkAIPPermissions(user, (SelectedItems<IndexedAIP>) selected, permissionType);
        } else if (classToReturn.equals(IndexedRepresentation.class)) {
            checkRepresentationPermissions(user, (SelectedItems<IndexedRepresentation>) selected, permissionType);
        } else if (classToReturn.equals(IndexedFile.class)) {
            checkFilePermissions(user, (SelectedItems<IndexedFile>) selected, permissionType);
        } else if (classToReturn.equals(IndexedDIP.class)) {
            checkDIPPermissions(user, (SelectedItems<IndexedDIP>) selected, permissionType);
        }
    }

    private static <T extends IsIndexed> void checkObjectPermissions(User user, SelectedItems<T> selected,
            Function<T, String> toAIP, PermissionType permission, List<String> fieldsToRequestIndex)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {

        if (isAdministrator(user)) {
            return;
        }

        Class<T> classToReturn = SelectedItemsUtils.parseClass(selected.getSelectedClass());
        IndexService index = RodaCoreFactory.getIndexService();
        if (selected instanceof SelectedItemsFilter) {
            SelectedItemsFilter<T> selectedItems = (SelectedItemsFilter<T>) selected;
            IterableIndexResult<T> findAll = index.findAll(classToReturn, selectedItems.getFilter(),
                    fieldsToRequestIndex);

            for (T obj : findAll) {
                String aipId = toAIP.apply(obj);
                IndexedAIP aip;
                try {
                    aip = index.retrieve(IndexedAIP.class, aipId, RodaConstants.AIP_PERMISSIONS_FIELDS_TO_RETURN);
                    checkAIPPermissions(user, aip, permission);
                } catch (NotFoundException e) {
                    // conservative approach
                    throw new AuthorizationDeniedException("Could not verify permissions of object ["
                            + classToReturn.getSimpleName() + "] " + obj.getUUID(), e);
                }

            }
        } else if (selected instanceof SelectedItemsList) {
            SelectedItemsList<T> selectedItems = (SelectedItemsList<T>) selected;

            List<IndexedAIP> aips = new ArrayList<>();
            for (String uuid : selectedItems.getIds()) {
                T obj;
                try {
                    obj = index.retrieve(classToReturn, uuid, fieldsToRequestIndex);
                    String aipId = toAIP.apply(obj);
                    IndexedAIP aip = index.retrieve(IndexedAIP.class, aipId,
                            RodaConstants.AIP_PERMISSIONS_FIELDS_TO_RETURN);
                    aips.add(aip);
                } catch (NotFoundException e) {
                    // conservative approach
                    throw new AuthorizationDeniedException("Could not verify permissions of object ["
                            + classToReturn.getSimpleName() + "] " + uuid, e);
                }

            }

            for (IndexedAIP aip : aips) {
                checkAIPPermissions(user, aip, permission);
            }
        } else {
            throw new RequestNotValidException(
                    "SelectedItems implementations not supported: " + selected.getClass().getName());
        }
    }

    public static void checkRepresentationPermissions(User user, SelectedItems<IndexedRepresentation> selected,
            PermissionType permission)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {
        checkObjectPermissions(user, selected, rep -> rep.getAipId(), permission,
                RodaConstants.REPRESENTATION_FIELDS_TO_RETURN);
    }

    public static void checkFilePermissions(User user, SelectedItems<IndexedFile> selected,
            PermissionType permission)
            throws AuthorizationDeniedException, GenericException, RequestNotValidException {
        checkObjectPermissions(user, selected, file -> file.getAipId(), permission,
                RodaConstants.FILE_FIELDS_TO_RETURN);
    }

    public static User resetGroupsAndRoles(User user) {
        List<Object> defaultRoles = RodaCoreFactory.getRodaConfiguration().getList(REGISTER_DEFAULT_ROLES);
        List<Object> defaultGroups = RodaCoreFactory.getRodaConfiguration().getList(REGISTER_DEFAULT_GROUPS);

        if (defaultRoles != null && !defaultRoles.isEmpty()) {
            user.setDirectRoles(new HashSet<String>(RodaUtils.copyList(defaultRoles)));
        } else {
            user.setDirectRoles(new HashSet<String>());
        }
        if (defaultGroups != null && !defaultGroups.isEmpty()) {
            user.setGroups(new HashSet<String>(RodaUtils.copyList(defaultGroups)));
        } else {
            user.setGroups(new HashSet<String>());
        }
        user.setActive(RodaCoreFactory.getRodaConfiguration().getBoolean(REGISTER_ACTIVE_PROPERTY));
        return user;
    }

}