blob: 3ab63f59015a2b8e4d66a570b10e1b4d24d8f1c7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.ranger.authorization.presto.authorizer;
import io.prestosql.spi.connector.CatalogSchemaName;
import io.prestosql.spi.connector.CatalogSchemaTableName;
import io.prestosql.spi.connector.SchemaTableName;
import io.prestosql.spi.security.AccessDeniedException;
import io.prestosql.spi.security.Identity;
import io.prestosql.spi.security.PrestoPrincipal;
import io.prestosql.spi.security.Privilege;
import io.prestosql.spi.security.SystemAccessControl;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static java.util.Locale.ENGLISH;
public class RangerSystemAccessControl
implements SystemAccessControl {
public static String RANGER_CONFIG_KEYTAB = "ranger.keytab";
public static String RANGER_CONFIG_PRINCIPAL = "ranger.principal";
public static String RANGER_PRESTO_SERVICETYPE = "presto";
public static String RANGER_PRESTO_APPID = "presto";
private static Logger LOG = LoggerFactory.getLogger(RangerSystemAccessControl.class);
private RangerBasePlugin rangerPlugin;
public RangerSystemAccessControl(Map<String, String> config) {
super();
if (config.get(RANGER_CONFIG_KEYTAB) != null && config.get(RANGER_CONFIG_PRINCIPAL) != null) {
String keytab = config.get(RANGER_CONFIG_KEYTAB);
String principal = config.get(RANGER_CONFIG_PRINCIPAL);
LOG.info("Performing kerberos login with principal " + principal + " and keytab " + keytab);
try {
UserGroupInformation.setConfiguration(new Configuration());
UserGroupInformation.loginUserFromKeytab(principal, keytab);
} catch (IOException ioe) {
LOG.error("Kerberos login failed", ioe);
throw new RuntimeException(ioe);
}
}
rangerPlugin = new RangerBasePlugin(RANGER_PRESTO_SERVICETYPE, RANGER_PRESTO_APPID);
rangerPlugin.init();
rangerPlugin.setResultProcessor(new RangerDefaultAuditHandler());
}
private boolean checkPermission(RangerPrestoResource resource, Identity identity, PrestoAccessType accessType) {
boolean ret = false;
UserGroupInformation ugi = UserGroupInformation.createRemoteUser(identity.getUser());
String[] groups = ugi != null ? ugi.getGroupNames() : null;
Set<String> userGroups = null;
if (groups != null && groups.length > 0) {
userGroups = new HashSet<>(Arrays.asList(groups));
}
RangerPrestoAccessRequest request = new RangerPrestoAccessRequest(
resource,
identity.getUser(),
userGroups,
accessType
);
RangerAccessResult result = rangerPlugin.isAccessAllowed(request);
if (result != null && result.getIsAllowed()) {
ret = true;
}
return ret;
}
@Override
public void checkCanSetUser(Optional<Principal> principal, String userName) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerSystemAccessControl.checkCanSetUser(" + userName + ")");
}
/*
if (!principal.isPresent()) {
//AccessDeniedException.denySetUser(principal, userName);
}*/
//AccessDeniedException.denySetUser(principal, userName);
}
@Override
public void checkCanSetSystemSessionProperty(Identity identity, String propertyName) {
if (!checkPermission(new RangerPrestoResource(), identity, PrestoAccessType.ADMIN)) {
LOG.info("==> RangerSystemAccessControl.checkCanSetSystemSessionProperty denied");
AccessDeniedException.denySetSystemSessionProperty(propertyName);
}
}
@Override
public void checkCanAccessCatalog(Identity identity, String catalogName) {
if (!checkPermission(createResource(catalogName), identity, PrestoAccessType.SELECT)) {
LOG.info("==> RangerSystemAccessControl.checkCanAccessCatalog(" + catalogName + ") denied");
AccessDeniedException.denyCatalogAccess(catalogName);
}
}
@Override
public Set<String> filterCatalogs(Identity identity, Set<String> catalogs) {
return catalogs;
}
@Override
public void checkCanCreateSchema(Identity identity, CatalogSchemaName schema) {
if (!checkPermission(createResource(schema.getCatalogName(), schema.getSchemaName()), identity, PrestoAccessType.CREATE)) {
LOG.info("==> RangerSystemAccessControl.checkCanCreateSchema(" + schema.getSchemaName() + ") denied");
AccessDeniedException.denyCreateSchema(schema.getSchemaName());
}
}
@Override
public void checkCanDropSchema(Identity identity, CatalogSchemaName schema) {
if (!checkPermission(createResource(schema.getCatalogName(), schema.getSchemaName()), identity, PrestoAccessType.DROP)) {
LOG.info("==> RangerSystemAccessControl.checkCanDropSchema(" + schema.getSchemaName() + ") denied");
AccessDeniedException.denyDropSchema(schema.getSchemaName());
}
}
@Override
public void checkCanRenameSchema(Identity identity, CatalogSchemaName schema, String newSchemaName) {
RangerPrestoResource res = createResource(schema.getCatalogName(), schema.getSchemaName());
if (!checkPermission(res, identity, PrestoAccessType.ALTER)) {
LOG.info("==> RangerSystemAccessControl.checkCanRenameSchema(" + schema.getSchemaName() + ") denied");
AccessDeniedException.denyRenameSchema(schema.getSchemaName(), newSchemaName);
}
}
@Override
public void checkCanShowSchemas(Identity identity, String catalogName) {
if (!checkPermission(createResource(catalogName), identity, PrestoAccessType.SELECT)) {
LOG.info("==> RangerSystemAccessControl.checkCanShowSchemas(" + catalogName + ") denied");
AccessDeniedException.denyShowSchemas(catalogName);
}
}
@Override
public Set<String> filterSchemas(Identity identity, String catalogName, Set<String> schemaNames) {
LOG.debug("==> RangerSystemAccessControl.filterSchemas(" + catalogName + ")");
return schemaNames;
}
@Override
public void checkCanCreateTable(Identity identity, CatalogSchemaTableName table) {
if (!checkPermission(createResource(table), identity, PrestoAccessType.CREATE)) {
LOG.info("==> RangerSystemAccessControl.checkCanCreateTable(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyCreateTable(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanDropTable(Identity identity, CatalogSchemaTableName table) {
if (!checkPermission(createResource(table), identity, PrestoAccessType.DROP)) {
LOG.info("==> RangerSystemAccessControl.checkCanDropTable(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyDropTable(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanRenameTable(Identity identity, CatalogSchemaTableName table, CatalogSchemaTableName newTable) {
RangerPrestoResource res = createResource(table);
if (!checkPermission(res, identity, PrestoAccessType.ALTER)) {
LOG.info("==> RangerSystemAccessControl.checkCanRenameTable(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyRenameTable(table.getSchemaTableName().getTableName(), newTable.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanShowTablesMetadata(Identity identity, CatalogSchemaName schema) {
if (!checkPermission(createResource(schema.getCatalogName(), schema.getSchemaName()), identity, PrestoAccessType.SELECT)) {
LOG.info("==> RangerSystemAccessControl.checkCanShowTablesMetadata(" + schema.getSchemaName() + ") denied");
AccessDeniedException.denyShowTablesMetadata(schema.getSchemaName());
}
}
@Override
public Set<SchemaTableName> filterTables(Identity identity, String catalogName, Set<SchemaTableName> tableNames) {
LOG.debug("==> RangerSystemAccessControl.filterTables(" + catalogName + ")");
return tableNames;
}
@Override
public void checkCanAddColumn(Identity identity, CatalogSchemaTableName table) {
RangerPrestoResource res = createResource(table);
if (!checkPermission(res, identity, PrestoAccessType.ALTER)) {
AccessDeniedException.denyAddColumn(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanDropColumn(Identity identity, CatalogSchemaTableName table) {
RangerPrestoResource res = createResource(table);
if (!checkPermission(res, identity, PrestoAccessType.ALTER)) {
LOG.info("==> RangerSystemAccessControl.checkCanDropColumn(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyDropColumn(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanRenameColumn(Identity identity, CatalogSchemaTableName table) {
RangerPrestoResource res = createResource(table);
if (!checkPermission(res, identity, PrestoAccessType.ALTER)) {
LOG.info("==> RangerSystemAccessControl.checkCanRenameColumn(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyRenameColumn(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanSelectFromColumns(Identity identity, CatalogSchemaTableName table, Set<String> columns) {
for (RangerPrestoResource res : createResource(table, columns)) {
if (!checkPermission(res, identity, PrestoAccessType.SELECT)) {
LOG.info("==> RangerSystemAccessControl.checkCanSelectFromColumns(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denySelectColumns(table.getSchemaTableName().getTableName(), columns);
}
}
}
@Override
public void checkCanInsertIntoTable(Identity identity, CatalogSchemaTableName table) {
RangerPrestoResource res = createResource(table);
if (!checkPermission(res, identity, PrestoAccessType.INSERT)) {
LOG.info("==> RangerSystemAccessControl.checkCanInsertIntoTable(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyInsertTable(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanDeleteFromTable(Identity identity, CatalogSchemaTableName table) {
if (!checkPermission(createResource(table), identity, PrestoAccessType.DELETE)) {
LOG.info("==> RangerSystemAccessControl.checkCanDeleteFromTable(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyDeleteTable(table.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanCreateView(Identity identity, CatalogSchemaTableName view) {
if (!checkPermission(createResource(view), identity, PrestoAccessType.CREATE)) {
LOG.info("==> RangerSystemAccessControl.checkCanCreateView(" + view.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyCreateView(view.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanDropView(Identity identity, CatalogSchemaTableName view) {
if (!checkPermission(createResource(view), identity, PrestoAccessType.DROP)) {
LOG.info("==> RangerSystemAccessControl.checkCanDropView(" + view.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyCreateView(view.getSchemaTableName().getTableName());
}
}
@Override
public void checkCanCreateViewWithSelectFromColumns(Identity identity, CatalogSchemaTableName table, Set<String> columns) {
for (RangerPrestoResource res : createResource(table, columns)) {
if (!checkPermission(res, identity, PrestoAccessType.CREATE)) {
LOG.info("==> RangerSystemAccessControl.checkCanDropView(" + table.getSchemaTableName().getTableName() + ") denied");
AccessDeniedException.denyCreateViewWithSelect(table.getSchemaTableName().getTableName(), identity);
}
}
}
@Override
public void checkCanSetCatalogSessionProperty(Identity identity, String catalogName, String propertyName) {
if (!checkPermission(createResource(catalogName), identity, PrestoAccessType.ADMIN)) {
LOG.info("==> RangerSystemAccessControl.checkCanSetSystemSessionProperty(" + catalogName + ") denied");
AccessDeniedException.denySetCatalogSessionProperty(catalogName, propertyName);
}
}
@Override
public void checkCanGrantTablePrivilege(Identity identity, Privilege privilege, CatalogSchemaTableName table, PrestoPrincipal grantee, boolean withGrantOption) {
if (!checkPermission(createResource(table), identity, PrestoAccessType.ADMIN)) {
LOG.info("==> RangerSystemAccessControl.checkCanGrantTablePrivilege(" + table + ") denied");
AccessDeniedException.denyGrantTablePrivilege(privilege.toString(), table.toString());
}
}
@Override
public void checkCanRevokeTablePrivilege(Identity identity, Privilege privilege, CatalogSchemaTableName table, PrestoPrincipal revokee, boolean grantOptionFor) {
if (!checkPermission(createResource(table), identity, PrestoAccessType.ADMIN)) {
LOG.info("==> RangerSystemAccessControl.checkCanRevokeTablePrivilege(" + table + ") denied");
AccessDeniedException.denyRevokeTablePrivilege(privilege.toString(), table.toString());
}
}
@Override
public void checkCanShowRoles(Identity identity, String catalogName) {
if (!checkPermission(createResource(catalogName), identity, PrestoAccessType.ADMIN)) {
LOG.info("==> RangerSystemAccessControl.checkCanShowRoles(" + catalogName + ") denied");
AccessDeniedException.denyShowRoles(catalogName);
}
}
private static RangerPrestoResource createResource(CatalogSchemaName catalogSchemaName) {
return createResource(catalogSchemaName.getCatalogName(), catalogSchemaName.getSchemaName());
}
private static RangerPrestoResource createResource(CatalogSchemaTableName catalogSchemaTableName) {
return createResource(catalogSchemaTableName.getCatalogName(),
catalogSchemaTableName.getSchemaTableName().getSchemaName(),
catalogSchemaTableName.getSchemaTableName().getTableName());
}
private static RangerPrestoResource createResource(String catalogName) {
return new RangerPrestoResource(catalogName, Optional.empty(), Optional.empty());
}
private static RangerPrestoResource createResource(String catalogName, String schemaName) {
return new RangerPrestoResource(catalogName, Optional.of(schemaName), Optional.empty());
}
private static RangerPrestoResource createResource(String catalogName, String schemaName, final String tableName) {
return new RangerPrestoResource(catalogName, Optional.of(schemaName), Optional.of(tableName));
}
private static RangerPrestoResource createResource(String catalogName, String schemaName, final String tableName, final Optional<String> column) {
return new RangerPrestoResource(catalogName, Optional.of(schemaName), Optional.of(tableName), column);
}
private static List<RangerPrestoResource> createResource(CatalogSchemaTableName table, Set<String> columns) {
List<RangerPrestoResource> colRequests = new ArrayList<>();
if (columns.size() > 0) {
for (String column : columns) {
RangerPrestoResource rangerPrestoResource = createResource(table.getCatalogName(),
table.getSchemaTableName().getSchemaName(),
table.getSchemaTableName().getTableName(), Optional.of(column));
colRequests.add(rangerPrestoResource);
}
} else {
colRequests.add(createResource(table.getCatalogName(),
table.getSchemaTableName().getSchemaName(),
table.getSchemaTableName().getTableName(), Optional.empty()));
}
return colRequests;
}
}
class RangerPrestoResource
extends RangerAccessResourceImpl {
public static final String KEY_CATALOG = "catalog";
public static final String KEY_SCHEMA = "schema";
public static final String KEY_TABLE = "table";
public static final String KEY_COLUMN = "column";
public RangerPrestoResource() {}
public RangerPrestoResource(String catalogName, Optional<String> schema, Optional<String> table) {
setValue(KEY_CATALOG, catalogName);
if (schema.isPresent()) {
setValue(KEY_SCHEMA, schema.get());
}
if (table.isPresent()) {
setValue(KEY_TABLE, table.get());
}
}
public RangerPrestoResource(String catalogName, Optional<String> schema, Optional<String> table, Optional<String> column) {
setValue(KEY_CATALOG, catalogName);
if (schema.isPresent()) {
setValue(KEY_SCHEMA, schema.get());
}
if (table.isPresent()) {
setValue(KEY_TABLE, table.get());
}
if (column.isPresent()) {
setValue(KEY_COLUMN, column.get());
}
}
public String getCatalogName() {
return (String) getValue(KEY_CATALOG);
}
public String getTable() {
return (String) getValue(KEY_TABLE);
}
public String getCatalog() {
return (String) getValue(KEY_CATALOG);
}
public String getSchema() { return (String) getValue(KEY_SCHEMA); }
public Optional<SchemaTableName> getSchemaTable() {
final String schema = getSchema();
if (StringUtils.isNotEmpty(schema)) {
return Optional.of(new SchemaTableName(schema, Optional.ofNullable(getTable()).orElse("*")));
}
return Optional.empty();
}
}
class RangerPrestoAccessRequest
extends RangerAccessRequestImpl {
public RangerPrestoAccessRequest(RangerPrestoResource resource,
String user,
Set<String> userGroups,
PrestoAccessType prestoAccessType)
{
super(resource,
prestoAccessType == PrestoAccessType.USE ? RangerPolicyEngine.ANY_ACCESS :
prestoAccessType == PrestoAccessType.ADMIN ? RangerPolicyEngine.ADMIN_ACCESS :
prestoAccessType.name().toLowerCase(ENGLISH), user,
userGroups);
}
}
enum PrestoAccessType {
CREATE, DROP, SELECT, INSERT, DELETE, USE, ALTER, ALL, ADMIN;
}