All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graylog2.migrations.V20200803120800_GrantsMigrations.UserPermissionsToGrantsMigration Maven / Gradle / Ivy

There is a newer version: 6.0.1
Show newest version
/*
 * Copyright (C) 2020 Graylog, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the Server Side Public License, version 1,
 * as published by MongoDB, Inc.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * Server Side Public License for more details.
 *
 * You should have received a copy of the Server Side Public License
 * along with this program. If not, see
 * .
 */
package org.graylog2.migrations.V20200803120800_GrantsMigrations;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.graylog.grn.GRN;
import org.graylog.grn.GRNRegistry;
import org.graylog.grn.GRNType;
import org.graylog.grn.GRNTypes;
import org.graylog.plugins.views.search.views.ViewService;
import org.graylog.security.Capability;
import org.graylog.security.DBGrantService;
import org.graylog2.migrations.V20200803120800_GrantsMigrations.GrantsMetaMigration.GRNTypeCapability;
import org.graylog2.plugin.database.ValidationException;
import org.graylog2.plugin.database.users.User;
import org.graylog2.shared.users.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Named;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Objects.requireNonNull;
import static org.graylog.plugins.views.search.rest.ViewsRestPermissions.VIEW_READ;

public class UserPermissionsToGrantsMigration {
    private static final Logger LOG = LoggerFactory.getLogger(UserPermissionsToGrantsMigration.class);
    private final UserService userService;
    private final DBGrantService dbGrantService;
    private final GRNRegistry grnRegistry;
    private final ViewService viewService;
    private final String rootUsername;

    public UserPermissionsToGrantsMigration(UserService userService,
                                            DBGrantService dbGrantService,
                                            GRNRegistry grnRegistry,
                                            ViewService viewService,
                                            @Named("root_username") String rootUsername) {
        this.userService = userService;
        this.dbGrantService = dbGrantService;
        this.grnRegistry = grnRegistry;
        this.viewService = viewService;
        this.rootUsername = rootUsername;
    }

    public void upgrade() {
        final List users = userService.loadAll();

        for (User user : users) {
            final Map> migratableEntities = getMigratableEntities(ImmutableSet.copyOf(user.getPermissions()));
            if (!migratableEntities.isEmpty()) {
                migrateUserPermissions(user, migratableEntities);
            }
        }
    }

    private Optional getViewGRNType(String viewId) {
        return viewService.get(viewId).map(view -> {
            final GRNType viewGrnType;
            switch (view.type()) {
                case SEARCH:
                    viewGrnType = GRNTypes.SEARCH;
                    break;
                case DASHBOARD:
                    viewGrnType = GRNTypes.DASHBOARD;
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + view.type());
            }
            return viewGrnType;
        });
    }

    private void migrateUserPermissions(User user, Map> migratableEntities) {
        migratableEntities.forEach((entityID, permissions) -> {
            final GRNTypeCapability grnTypeCapability = GrantsMetaMigration.MIGRATION_MAP.get(permissions);

            // Permissions are mappable to a grant
            if (grnTypeCapability != null) {
                final Capability capability = grnTypeCapability.capability;

                GRN targetGRN;
                if (permissions.stream().anyMatch(p -> p.contains(VIEW_READ))) {
                    // For views we need to load the database object to be able to determine if it's a
                    // search or a dashboard.
                    targetGRN = getViewGRNType(entityID).map(grnType -> grnType.toGRN(entityID)).orElse(null);
                } else {
                    targetGRN = requireNonNull(grnTypeCapability.grnType, "grnType cannot be null - this is a bug").toGRN(entityID);
                }

                if (targetGRN != null) {
                    dbGrantService.ensure(grnRegistry.ofUser(user), capability, targetGRN, rootUsername);
                }

                final List updatedPermissions = user.getPermissions();
                updatedPermissions.removeAll(permissions.stream().map(p -> p + ":" + entityID).collect(Collectors.toSet()));
                user.setPermissions(updatedPermissions);
                try {
                    userService.save(user);
                } catch (ValidationException e) {
                    LOG.error("Failed to update permssions on user <{}>", user.getName(), e);
                }
                LOG.info("Migrating entity <{}> permissions <{}> to <{}> grant for user <{}>", targetGRN, permissions, capability, user.getName());
            } else {
                LOG.info("Skipping non-migratable entity <{}>. Permissions <{}> cannot be converted to a grant capability", entityID, permissions);
            }
        });
    }

    private Map> getMigratableEntities(Set permissions) {
        Map> migratableEntities = new HashMap<>();

        permissions.stream().map(GrantsMetaMigration.MigrationWildcardPermission::new)
                .filter(p -> p.getParts().size() == 3 && p.getParts().stream().allMatch(part -> part.size() == 1))
                .forEach(p -> {
                    String permissionType = p.subPart(0);
                    String restPermission = p.subPart(0) + ":" + p.subPart(1);
                    String id = p.subPart(2);

                    if (GrantsMetaMigration.MIGRATION_MAP.keySet().stream().flatMap(Collection::stream).anyMatch(perm -> perm.startsWith(permissionType + ":"))) {
                        if (migratableEntities.containsKey(id)) {
                            migratableEntities.get(id).add(restPermission);
                        } else {
                            migratableEntities.put(id, Sets.newHashSet(restPermission));
                        }
                    }
                });
        return migratableEntities;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy