Skip to content

Commit

Permalink
Add file based system access control
Browse files Browse the repository at this point in the history
The current implementation handles only the catalog access
control rules specified in a file. Using these rules,
one can restrict access to specified catalogs to the
specified users.

By default, all users have access to the "system" catalog to
facilitate debugging via "select * from system.runtime.nodes".
  • Loading branch information
Amruta Gokhale authored and dain committed Jun 10, 2017
1 parent 36a68e6 commit 3de5d12
Show file tree
Hide file tree
Showing 5 changed files with 518 additions and 0 deletions.
@@ -0,0 +1,49 @@
/*
* 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 com.facebook.presto.security;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Optional;
import java.util.regex.Pattern;

import static java.util.Objects.requireNonNull;

public class CatalogAccessControlRule
{
private final boolean allow;
private final Optional<Pattern> userRegex;
private final Optional<Pattern> catalogRegex;

@JsonCreator
public CatalogAccessControlRule(
@JsonProperty("allow") boolean allow,
@JsonProperty("user") Optional<Pattern> userRegex,
@JsonProperty("catalog") Optional<Pattern> catalogRegex)
{
this.allow = allow;
this.userRegex = requireNonNull(userRegex, "userRegex is null");
this.catalogRegex = requireNonNull(catalogRegex, "catalogRegex is null");
}

public Optional<Boolean> match(String user, String catalog)
{
if (userRegex.map(regex -> regex.matcher(user).matches()).orElse(true) &&
catalogRegex.map(regex -> regex.matcher(catalog).matches()).orElse(true)) {
return Optional.of(allow);
}
return Optional.empty();
}
}
@@ -0,0 +1,251 @@
/*
* 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 com.facebook.presto.security;

import com.facebook.presto.spi.CatalogSchemaName;
import com.facebook.presto.spi.CatalogSchemaTableName;
import com.facebook.presto.spi.SchemaTableName;
import com.facebook.presto.spi.security.Identity;
import com.facebook.presto.spi.security.Privilege;
import com.facebook.presto.spi.security.SystemAccessControl;
import com.facebook.presto.spi.security.SystemAccessControlFactory;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Principal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

import static com.google.common.base.Preconditions.checkState;
import static io.airlift.json.JsonCodec.jsonCodec;
import static java.util.Objects.requireNonNull;

public class FileBasedSystemAccessControl
implements SystemAccessControl
{
public static final String NAME = "file";

private final List<CatalogAccessControlRule> catalogRules;

private FileBasedSystemAccessControl(List<CatalogAccessControlRule> catalogRules)
{
this.catalogRules = catalogRules;
}

public static class Factory
implements SystemAccessControlFactory
{
private static final String CONFIG_FILE_NAME = "security.config-file";

@Override
public String getName()
{
return NAME;
}

@Override
public SystemAccessControl create(Map<String, String> config)
{
requireNonNull(config, "config is null");

String configFileName = config.get(CONFIG_FILE_NAME);
checkState(
configFileName != null,
"Security configuration must contain the '%s' property", CONFIG_FILE_NAME);

try {
Path path = Paths.get(configFileName);
if (!path.isAbsolute()) {
path = path.toAbsolutePath();
}
path.toFile().canRead();

ImmutableList.Builder<CatalogAccessControlRule> catalogRulesBuilder = ImmutableList.builder();
catalogRulesBuilder.addAll(jsonCodec(FileBasedSystemAccessControlRules.class)
.fromJson(Files.readAllBytes(path))
.getCatalogRules());

// Hack to allow Presto Admin to access the "system" catalog for retrieving server status.
// todo Change userRegex from ".*" to one particular user that Presto Admin will be restricted to run as
catalogRulesBuilder.add(new CatalogAccessControlRule(
true,
Optional.of(Pattern.compile(".*")),
Optional.of(Pattern.compile("system"))));

return new FileBasedSystemAccessControl(catalogRulesBuilder.build());
}
catch (SecurityException | IOException | InvalidPathException e) {
throw new RuntimeException(e);
}
}
}

@Override
public void checkCanSetUser(Principal principal, String userName)
{
}

@Override
public void checkCanSetSystemSessionProperty(Identity identity, String propertyName)
{
}

@Override
public Set<String> filterCatalogs(Identity identity, Set<String> catalogs)
{
ImmutableSet.Builder<String> filteredCatalogs = ImmutableSet.builder();
for (String catalog : catalogs) {
if (canAccessCatalog(identity, catalog)) {
filteredCatalogs.add(catalog);
}
}
return filteredCatalogs.build();
}

private boolean canAccessCatalog(Identity identity, String catalogName)
{
for (CatalogAccessControlRule rule : catalogRules) {
Optional<Boolean> allowed = rule.match(identity.getUser(), catalogName);
if (allowed.isPresent()) {
return allowed.get();
}
}
return false;
}

@Override
public void checkCanCreateSchema(Identity identity, CatalogSchemaName schema)
{
}

@Override
public void checkCanDropSchema(Identity identity, CatalogSchemaName schema)
{
}

@Override
public void checkCanRenameSchema(Identity identity, CatalogSchemaName schema, String newSchemaName)
{
}

@Override
public void checkCanShowSchemas(Identity identity, String catalogName)
{
}

@Override
public Set<String> filterSchemas(Identity identity, String catalogName, Set<String> schemaNames)
{
return schemaNames;
}

@Override
public void checkCanCreateTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanDropTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanRenameTable(Identity identity, CatalogSchemaTableName table, CatalogSchemaTableName newTable)
{
}

@Override
public void checkCanShowTablesMetadata(Identity identity, CatalogSchemaName schema)
{
}

@Override
public Set<SchemaTableName> filterTables(Identity identity, String catalogName, Set<SchemaTableName> tableNames)
{
return tableNames;
}

@Override
public void checkCanAddColumn(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanRenameColumn(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanSelectFromTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanInsertIntoTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanDeleteFromTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanCreateView(Identity identity, CatalogSchemaTableName view)
{
}

@Override
public void checkCanDropView(Identity identity, CatalogSchemaTableName view)
{
}

@Override
public void checkCanSelectFromView(Identity identity, CatalogSchemaTableName view)
{
}

@Override
public void checkCanCreateViewWithSelectFromTable(Identity identity, CatalogSchemaTableName table)
{
}

@Override
public void checkCanCreateViewWithSelectFromView(Identity identity, CatalogSchemaTableName view)
{
}

@Override
public void checkCanSetCatalogSessionProperty(Identity identity, String catalogName, String propertyName)
{
}

@Override
public void checkCanGrantTablePrivilege(Identity identity, Privilege privilege, CatalogSchemaTableName table)
{
}

@Override
public void checkCanRevokeTablePrivilege(Identity identity, Privilege privilege, CatalogSchemaTableName table)
{
}
}
@@ -0,0 +1,37 @@
/*
* 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 com.facebook.presto.security;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableList;

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

public class FileBasedSystemAccessControlRules
{
private final List<CatalogAccessControlRule> catalogRules;

@JsonCreator
public FileBasedSystemAccessControlRules(@JsonProperty("catalogs") Optional<List<CatalogAccessControlRule>> catalogRules)
{
this.catalogRules = catalogRules.map(ImmutableList::copyOf).orElse(ImmutableList.of());
}

public List<CatalogAccessControlRule> getCatalogRules()
{
return catalogRules;
}
}

0 comments on commit 3de5d12

Please sign in to comment.