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

org.graylog.security.DBGrantService Maven / Gradle / Ivy

There is a newer version: 6.1.4
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.graylog.security;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.mongodb.BasicDBObject;
import org.graylog.grn.GRN;
import org.graylog.grn.GRNRegistry;
import org.graylog2.bindings.providers.MongoJackObjectMapperProvider;
import org.graylog2.database.MongoConnection;
import org.graylog2.database.PaginatedDbService;
import org.graylog2.plugin.database.users.User;
import org.mongojack.DBQuery;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

public class DBGrantService extends PaginatedDbService {
    public static final String COLLECTION_NAME = "grants";

    private final GRNRegistry grnRegistry;

    @Inject
    public DBGrantService(MongoConnection mongoConnection,
                          MongoJackObjectMapperProvider mapper,
                          GRNRegistry grnRegistry) {
        super(mongoConnection, mapper, GrantDTO.class, COLLECTION_NAME);
        this.grnRegistry = grnRegistry;

        db.createIndex(new BasicDBObject(GrantDTO.FIELD_GRANTEE, 1));
        db.createIndex(new BasicDBObject(GrantDTO.FIELD_TARGET, 1));
        db.createIndex(
                new BasicDBObject(GrantDTO.FIELD_GRANTEE, 1)
                        .append(GrantDTO.FIELD_CAPABILITY, 1)
                        .append(GrantDTO.FIELD_TARGET, 1),
                new BasicDBObject("unique", true));
        db.createIndex(
                new BasicDBObject(GrantDTO.FIELD_GRANTEE, 1)
                        .append(GrantDTO.FIELD_TARGET, 1),
                new BasicDBObject("unique", true));
        // TODO: Add more indices
    }

    public ImmutableSet getForGranteesOrGlobal(Set grantees) {
        return streamQuery(DBQuery.or(
                DBQuery.in(GrantDTO.FIELD_GRANTEE, grantees),
                DBQuery.is(GrantDTO.FIELD_GRANTEE, GRNRegistry.GLOBAL_USER_GRN.toString())
        )).collect(ImmutableSet.toImmutableSet());
    }

    public ImmutableSet getForGrantee(GRN grantee) {
        return streamQuery(DBQuery.is(GrantDTO.FIELD_GRANTEE, grantee))
                .collect(ImmutableSet.toImmutableSet());
    }

    public ImmutableSet getForGranteeWithCapability(GRN grantee, Capability capability) {
        return streamQuery(DBQuery.and(
                DBQuery.is(GrantDTO.FIELD_GRANTEE, grantee),
                DBQuery.is(GrantDTO.FIELD_CAPABILITY, capability)
        )).collect(ImmutableSet.toImmutableSet());
    }

    public ImmutableSet getForGranteesOrGlobalWithCapability(Set grantees, Capability capability) {
        return streamQuery(DBQuery.and(
                DBQuery.or(
                        DBQuery.in(GrantDTO.FIELD_GRANTEE, grantees),
                        DBQuery.is(GrantDTO.FIELD_GRANTEE, GRNRegistry.GLOBAL_USER_GRN.toString())
                ),
                DBQuery.is(GrantDTO.FIELD_CAPABILITY, capability)
        )).collect(ImmutableSet.toImmutableSet());
    }

    public List getForTargetAndGrantee(GRN target, GRN grantee) {
        return getForTargetAndGrantees(target, ImmutableSet.of(grantee));
    }

    public List getForTargetAndGrantees(GRN target, Set grantees) {
        return db.find(DBQuery.and(
                DBQuery.is(GrantDTO.FIELD_TARGET, target),
                DBQuery.in(GrantDTO.FIELD_GRANTEE, grantees))).toArray();
    }

    public GrantDTO create(GrantDTO grantDTO, @Nullable User currentUser) {
        return create(grantDTO, requireNonNull(currentUser, "currentUser cannot be null").getName());
    }

    public GrantDTO create(GrantDTO grantDTO, String creatorUsername) {
        checkArgument(isNotBlank(creatorUsername), "creatorUsername cannot be null or empty");
        final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);

        return save(grantDTO.toBuilder()
                .createdBy(creatorUsername)
                .createdAt(now)
                .updatedBy(creatorUsername)
                .updatedAt(now)
                .build());
    }

    public GrantDTO create(GRN grantee, Capability capability, GRN target, String creatorUsername) {
        checkArgument(grantee != null, "grantee cannot be null");
        checkArgument(capability != null, "capability cannot be null");
        checkArgument(target != null, "target cannot be null");

        return create(GrantDTO.of(grantee, capability, target), creatorUsername);
    }

    /**
     * Ensure that a grant with the requested or a higher capability exists.
     *
     * @return the created, updated or existing grant
     */
    public GrantDTO ensure(GRN grantee, Capability capability, GRN target, String creatorUsername) {
        final List existingGrants = getForTargetAndGrantee(target, grantee);
        if (existingGrants.isEmpty()) {
            return create(grantee, capability, target, creatorUsername);
        }
        // This should never happen
        Preconditions.checkState(existingGrants.size() == 1);

        final GrantDTO grantDTO = existingGrants.get(0);
        // Only upgrade capabilities: VIEW < MANAGE < OWNER
        if (capability.priority() > grantDTO.capability().priority()) {
            final GrantDTO grantUpdate = grantDTO.toBuilder().capability(capability).build();
            return save(grantUpdate);
        }
        return grantDTO;
    }

    public GrantDTO update(GrantDTO updatedGrant, @Nullable User currentUser) {
        final GrantDTO existingGrant = get(updatedGrant.id())
                .orElseThrow(() -> new IllegalArgumentException("Couldn't find grant with ID " + updatedGrant.id()));

        return save(existingGrant.toBuilder()
                .grantee(updatedGrant.grantee())
                .capability(updatedGrant.capability())
                .target(updatedGrant.target())
                .updatedBy(requireNonNull(currentUser, "currentUser cannot be null").getName())
                .updatedAt(ZonedDateTime.now(ZoneOffset.UTC))
                .build());
    }

    public ImmutableList getAll() {
        try (final Stream stream = streamAll()) {
            return stream.collect(ImmutableList.toImmutableList());
        }
    }

    public List getForTarget(GRN target) {
        return db.find(DBQuery.is(GrantDTO.FIELD_TARGET, target.toString())).toArray();
    }

    public int deleteForGrantee(GRN grantee) {
        return db.remove(DBQuery.is(GrantDTO.FIELD_GRANTEE, grantee.toString())).getN();
    }

    public int deleteForTarget(GRN target) {
        return db.remove(DBQuery.is(GrantDTO.FIELD_TARGET, target.toString())).getN();
    }

    public List getForTargetExcludingGrantee(GRN target, GRN grantee) {
        return db.find(DBQuery.and(
                DBQuery.is(GrantDTO.FIELD_TARGET, target.toString()),
                DBQuery.notEquals(GrantDTO.FIELD_GRANTEE, grantee.toString())
        )).toArray();
    }

    public Map> getOwnersForTargets(Collection targets) {
        return db.find(DBQuery.and(
                DBQuery.in(GrantDTO.FIELD_TARGET, targets),
                DBQuery.is(GrantDTO.FIELD_CAPABILITY, Capability.OWN)
        )).toArray()
                .stream()
                .collect(Collectors.groupingBy(
                        GrantDTO::target,
                        Collectors.mapping(GrantDTO::grantee, Collectors.toSet())
                ));
    }

    public boolean hasGrantFor(GRN grantee, Capability capability, GRN target) {
        return db.findOne(DBQuery.and(
                DBQuery.is(GrantDTO.FIELD_GRANTEE, grantee),
                DBQuery.is(GrantDTO.FIELD_CAPABILITY, capability),
                DBQuery.is(GrantDTO.FIELD_TARGET, target)
        )) != null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy