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

io.trino.plugin.hive.security.SqlStandardAccessControlMetadata Maven / Gradle / Ivy

Go to download

This is a Databricks build of Trino's Hive plugin which includes support for HTTP based transport for it's Hive metastore thrift interface.

The newest version!
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.trino.plugin.hive.security;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import io.trino.plugin.hive.HiveViewNotSupportedException;
import io.trino.plugin.hive.metastore.HivePrincipal;
import io.trino.plugin.hive.metastore.HivePrivilegeInfo;
import io.trino.plugin.hive.metastore.thrift.ThriftMetastoreUtil;
import io.trino.spi.TrinoException;
import io.trino.spi.connector.ConnectorSession;
import io.trino.spi.connector.SchemaTableName;
import io.trino.spi.connector.TableNotFoundException;
import io.trino.spi.security.GrantInfo;
import io.trino.spi.security.Privilege;
import io.trino.spi.security.PrivilegeInfo;
import io.trino.spi.security.RoleGrant;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static io.trino.plugin.hive.security.SqlStandardAccessControl.ADMIN_ROLE_NAME;
import static io.trino.spi.StandardErrorCode.ALREADY_EXISTS;
import static io.trino.spi.security.PrincipalType.USER;
import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;
import static java.util.function.Predicate.not;
import static java.util.stream.Collectors.toSet;

public class SqlStandardAccessControlMetadata
        implements AccessControlMetadata
{
    private static final Set RESERVED_ROLES = ImmutableSet.of("all", "default", "none");

    private final SqlStandardAccessControlMetadataMetastore metastore;

    public SqlStandardAccessControlMetadata(SqlStandardAccessControlMetadataMetastore metastore)
    {
        this.metastore = requireNonNull(metastore, "metastore is null");
    }

    @Override
    public void createRole(ConnectorSession session, String role, Optional grantor)
    {
        checkRoleIsNotReserved(role);
        metastore.createRole(role, null);
    }

    @Override
    public void dropRole(ConnectorSession session, String role)
    {
        checkRoleIsNotReserved(role);
        metastore.dropRole(role);
    }

    private static void checkRoleIsNotReserved(String role)
    {
        // roles are case insensitive in Hive
        if (RESERVED_ROLES.contains(role.toLowerCase(ENGLISH))) {
            throw new TrinoException(ALREADY_EXISTS, "Role name cannot be one of the reserved roles: " + RESERVED_ROLES);
        }
    }

    @Override
    public Set listRoles(ConnectorSession session)
    {
        return ImmutableSet.copyOf(metastore.listRoles());
    }

    @Override
    public Set listRoleGrants(ConnectorSession session, HivePrincipal principal)
    {
        return ImmutableSet.copyOf(metastore.listRoleGrants(principal));
    }

    @Override
    public void grantRoles(ConnectorSession session, Set roles, Set grantees, boolean adminOption, Optional grantor)
    {
        metastore.grantRoles(roles, grantees, adminOption, grantor.orElse(new HivePrincipal(USER, session.getUser())));
    }

    @Override
    public void revokeRoles(ConnectorSession session, Set roles, Set grantees, boolean adminOption, Optional grantor)
    {
        metastore.revokeRoles(roles, grantees, adminOption, grantor.orElse(new HivePrincipal(USER, session.getUser())));
    }

    @Override
    public Set listApplicableRoles(ConnectorSession session, HivePrincipal principal)
    {
        return ThriftMetastoreUtil.listApplicableRoles(principal, metastore::listRoleGrants)
                .collect(toImmutableSet());
    }

    @Override
    public Set listEnabledRoles(ConnectorSession session)
    {
        return ThriftMetastoreUtil.listEnabledRoles(session.getIdentity(), metastore::listRoleGrants)
                .collect(toImmutableSet());
    }

    @Override
    public Optional getSchemaOwner(ConnectorSession session, String schemaName)
    {
        return metastore.getDatabaseOwner(schemaName);
    }

    @Override
    public void grantTablePrivileges(ConnectorSession session, SchemaTableName schemaTableName, Set privileges, HivePrincipal grantee, boolean grantOption)
    {
        String schemaName = schemaTableName.getSchemaName();
        String tableName = schemaTableName.getTableName();

        // Hive does not support the CREATE privilege, so ignore. Normally we would throw
        // an error for this, but when the Trino engine sees ALL_PRIVILEGES, it sends the
        // enumerated list of privileges instead of an Optional.empty
        privileges = privileges.stream()
                .filter(not(Privilege.CREATE::equals))
                .collect(toImmutableSet());

        metastore.grantTablePrivileges(
                schemaName,
                tableName,
                grantee,
                new HivePrincipal(USER, session.getUser()),
                privileges.stream()
                        .map(HivePrivilegeInfo::toHivePrivilege)
                        .collect(toSet()),
                grantOption);
    }

    @Override
    public void revokeTablePrivileges(ConnectorSession session, SchemaTableName schemaTableName, Set privileges, HivePrincipal grantee, boolean grantOption)
    {
        String schemaName = schemaTableName.getSchemaName();
        String tableName = schemaTableName.getTableName();

        // Hive does not support the CREATE privilege, so ignore. Normally we would throw
        // an error for this, but when the Trino engine sees ALL_PRIVILEGES, it sends the
        // enumerated list of privileges instead of an Optional.empty
        privileges = privileges.stream()
                .filter(not(Privilege.CREATE::equals))
                .collect(toImmutableSet());

        metastore.revokeTablePrivileges(
                schemaName,
                tableName,
                grantee,
                new HivePrincipal(USER, session.getUser()),
                privileges.stream()
                        .map(HivePrivilegeInfo::toHivePrivilege)
                        .collect(toSet()),
                grantOption);
    }

    @Override
    public List listTablePrivileges(ConnectorSession session, List tableNames)
    {
        Set principals = ThriftMetastoreUtil.listEnabledPrincipals(session.getIdentity(), metastore::listRoleGrants)
                .collect(toImmutableSet());
        boolean isAdminRoleSet = hasAdminRole(principals);
        ImmutableList.Builder result = ImmutableList.builder();
        for (SchemaTableName tableName : tableNames) {
            try {
                result.addAll(buildGrants(principals, isAdminRoleSet, tableName));
            }
            catch (TableNotFoundException e) {
                // table disappeared during listing operation
            }
            catch (HiveViewNotSupportedException e) {
                // table is an unsupported hive view but shouldn't fail listTablePrivileges.
            }
        }
        return result.build();
    }

    private List buildGrants(Set principals, boolean isAdminRoleSet, SchemaTableName tableName)
    {
        if (isAdminRoleSet) {
            return buildGrants(tableName, Optional.empty());
        }
        ImmutableList.Builder result = ImmutableList.builder();
        for (HivePrincipal grantee : principals) {
            result.addAll(buildGrants(tableName, Optional.of(grantee)));
        }
        return result.build();
    }

    private List buildGrants(SchemaTableName tableName, Optional principal)
    {
        ImmutableList.Builder result = ImmutableList.builder();
        Set hivePrivileges = metastore.listTablePrivileges(tableName.getSchemaName(), tableName.getTableName(), principal);
        for (HivePrivilegeInfo hivePrivilege : hivePrivileges) {
            Set prestoPrivileges = hivePrivilege.toPrivilegeInfo();
            for (PrivilegeInfo prestoPrivilege : prestoPrivileges) {
                GrantInfo grant = new GrantInfo(
                        prestoPrivilege,
                        hivePrivilege.getGrantee().toTrinoPrincipal(),
                        tableName,
                        Optional.of(hivePrivilege.getGrantor().toTrinoPrincipal()),
                        Optional.empty());
                result.add(grant);
            }
        }
        return result.build();
    }

    private static boolean hasAdminRole(Set roles)
    {
        return roles.stream().anyMatch(principal -> principal.getName().equalsIgnoreCase(ADMIN_ROLE_NAME));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy