Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Provide user access to all tables except tableX #14839

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,15 @@ public static UserConfig fromZNRecord(ZNRecord znRecord) {
String role = simpleFields.get(UserConfig.ROLE_KEY);

List<String> tableList = znRecord.getListField(UserConfig.TABLES_KEY);
List<String> excludeTableList = znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY);

List<String> permissionListFromZNRecord = znRecord.getListField(UserConfig.PERMISSIONS_KEY);
List<AccessType> permissionList = null;
if (permissionListFromZNRecord != null) {
permissionList = permissionListFromZNRecord.stream()
.map(x -> AccessType.valueOf(x)).collect(Collectors.toList());
}
return new UserConfig(username, password, component, role, tableList, permissionList);
return new UserConfig(username, password, component, role, tableList, excludeTableList, permissionList);
}

public static ZNRecord toZNRecord(UserConfig userConfig)
Expand All @@ -73,6 +74,10 @@ public static ZNRecord toZNRecord(UserConfig userConfig)
if (tableList != null) {
listFields.put(UserConfig.TABLES_KEY, userConfig.getTables());
}
List<String> excludeTableList = userConfig.getExcludeTables();
if (excludeTableList != null) {
listFields.put(UserConfig.EXCLUDE_TABLES_KEY, userConfig.getExcludeTables());
}

List<AccessType> permissionList = userConfig.getPermissios();
if (permissionList != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1625,12 +1625,14 @@ public void initUserACLConfig(ControllerConf controllerConf)
if (CollectionUtils.isEmpty(ZKMetadataProvider.getAllUserName(_propertyStore))) {
String initUsername = controllerConf.getInitAccessControlUsername();
String initPassword = controllerConf.getInitAccessControlPassword();
addUser(new UserConfig(initUsername, initPassword, ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), null,
null));
addUser(new UserConfig(initUsername, initPassword, ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(),
null, null, null));
addUser(
new UserConfig(initUsername, initPassword, ComponentType.BROKER.name(), RoleType.ADMIN.name(), null, null));
new UserConfig(initUsername, initPassword, ComponentType.BROKER.name(), RoleType.ADMIN.name(),
null, null, null));
addUser(
new UserConfig(initUsername, initPassword, ComponentType.SERVER.name(), RoleType.ADMIN.name(), null, null));
new UserConfig(initUsername, initPassword, ComponentType.SERVER.name(), RoleType.ADMIN.name(),
null, null, null));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,15 @@ public class BasicAuthPrincipal {
private final String _name;
private final String _token;
private final Set<String> _tables;
private final Set<String> _excludeTables;
private final Set<String> _permissions;

public BasicAuthPrincipal(String name, String token, Set<String> tables, Set<String> permissions) {
public BasicAuthPrincipal(String name, String token, Set<String> tables, Set<String> excludeTables,
Set<String> permissions) {
_name = name;
_token = token;
_tables = tables;
_excludeTables = excludeTables;
_permissions = permissions.stream().map(s -> s.toLowerCase()).collect(Collectors.toSet());
}

Expand All @@ -47,9 +50,17 @@ public String getToken() {
}

public boolean hasTable(String tableName) {
return isTableIncluded(tableName) && isTableNotExcluded(tableName);
}

private boolean isTableIncluded(String tableName) {
return _tables.isEmpty() || _tables.contains(tableName);
}

private boolean isTableNotExcluded(String tableName) {
return !_excludeTables.contains(tableName);
}

public boolean hasPermission(String permission) {
return _permissions.isEmpty() || _permissions.contains(permission.toLowerCase());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public final class BasicAuthUtils {
private static final String PASSWORD = "password";
private static final String PERMISSIONS = "permissions";
private static final String TABLES = "tables";
private static final String EXCLUDE_TABLES = "excludeTables";
private static final String ALL = "*";

private BasicAuthUtils() {
Expand Down Expand Up @@ -72,10 +73,11 @@ public static List<BasicAuthPrincipal> extractBasicAuthPrincipals(PinotConfigura
Preconditions.checkArgument(StringUtils.isNotBlank(password), "must provide a password for %s", name);

Set<String> tables = extractSet(configuration, prefix + "." + name + "." + TABLES);
Set<String> excludeTables = extractSet(configuration, prefix + "." + name + "." + EXCLUDE_TABLES);
Set<String> permissions = extractSet(configuration, prefix + "." + name + "." + PERMISSIONS);

return new BasicAuthPrincipal(name, org.apache.pinot.common.auth.BasicAuthUtils.toBasicAuthToken(name, password),
tables, permissions);
tables, excludeTables, permissions);
}).collect(Collectors.toList());
}

Expand All @@ -92,13 +94,16 @@ public static List<ZkBasicAuthPrincipal> extractBasicAuthPrincipals(List<UserCon
Set<String> tables = Optional.ofNullable(user.getTables())
.orElseGet(() -> Collections.emptyList())
.stream().collect(Collectors.toSet());
Set<String> excludeTables = Optional.ofNullable(user.getExcludeTables())
.orElseGet(() -> Collections.emptyList())
.stream().collect(Collectors.toSet());
Set<String> permissions = Optional.ofNullable(user.getPermissios())
.orElseGet(() -> Collections.emptyList())
.stream().map(x -> x.toString())
.collect(Collectors.toSet());
return new ZkBasicAuthPrincipal(name,
org.apache.pinot.common.auth.BasicAuthUtils.toBasicAuthToken(name, password), password,
component, role, tables, permissions);
component, role, tables, excludeTables, permissions);
}).collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public class ZkBasicAuthPrincipal extends BasicAuthPrincipal {
private final String _role;

public ZkBasicAuthPrincipal(String name, String token, String password, String component, String role,
Set<String> tables, Set<String> permissions) {
super(name, token, tables, permissions);
Set<String> tables, Set<String> excludeTables, Set<String> permissions) {
super(name, token, tables, excludeTables, permissions);
_component = component;
_role = role;
_password = password;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,48 @@
package org.apache.pinot.core.auth;

import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import org.testng.Assert;
import org.testng.annotations.Test;


public class BasicAuthTest {

@Test
public void testBasicAuthPrincipal()
throws Exception {
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("READ"))
public void testBasicAuthPrincipal() {
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("READ"))
.hasTable("myTable"));
Assert.assertTrue(
new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable", "myTable1"), ImmutableSet.of("Read"))
.hasTable("myTable1"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("read"))
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable", "myTable1"),
Collections.emptySet(), ImmutableSet.of("Read"))
.hasTable("myTable1"));
Assert.assertFalse(
new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable", "myTable1"), ImmutableSet.of("read"))
.hasTable("myTable2"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("read"))
.hasTable("myTable1"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable", "myTable1"),
Collections.emptySet(), ImmutableSet.of("read"))
.hasTable("myTable2"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("myTable"),
ImmutableSet.of("read"))
.hasTable("myTable"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", Collections.emptySet(), ImmutableSet.of("myTable"),
ImmutableSet.of("read"))
.hasTable("myTable"));
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("myTable1"),
ImmutableSet.of("read"))
.hasTable("myTable"));

Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("READ"))
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("READ"))
.hasPermission("read"));
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("Read"))
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("Read"))
.hasPermission("READ"));
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("read"))
Assert.assertTrue(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("read"))
.hasPermission("Read"));
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), ImmutableSet.of("read"))
Assert.assertFalse(new BasicAuthPrincipal("name", "token", ImmutableSet.of("myTable"), Collections.emptySet(),
ImmutableSet.of("read"))
.hasPermission("write"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.pinot.core.auth;

import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import org.apache.pinot.spi.config.user.ComponentType;
import org.apache.pinot.spi.config.user.RoleType;
import org.testng.Assert;
Expand All @@ -28,32 +29,40 @@
public class ZkBasicAuthTest {

@Test
public void testBasicAuthPrincipal()
throws Exception {
public void testBasicAuthPrincipal() {
Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("READ")).hasTable("myTable"));
Collections.emptySet(), ImmutableSet.of("READ")).hasTable("myTable"));
Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable", "myTable1"),
ImmutableSet.of("Read")).hasTable("myTable1"));
Collections.emptySet(), ImmutableSet.of("Read")).hasTable("myTable1"));
Assert.assertFalse(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("read")).hasTable("myTable1"));
Collections.emptySet(), ImmutableSet.of("read")).hasTable("myTable1"));
Assert.assertFalse(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable", "myTable1"),
ImmutableSet.of("read")).hasTable("myTable2"));
Collections.emptySet(), ImmutableSet.of("read")).hasTable("myTable2"));
Assert.assertFalse(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable", "myTable1"),
ImmutableSet.of("myTable3"), ImmutableSet.of("Read")).hasTable("myTable3"));
Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable", "myTable1"),
ImmutableSet.of("myTable"), ImmutableSet.of("read")).hasTable("myTable1"));
Assert.assertFalse(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), Collections.emptySet(),
ImmutableSet.of("myTable"), ImmutableSet.of("read")).hasTable("myTable"));

Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("READ")).hasPermission("read"));
Collections.emptySet(), ImmutableSet.of("READ")).hasPermission("read"));
Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("Read")).hasPermission("READ"));
Collections.emptySet(), ImmutableSet.of("Read")).hasPermission("READ"));
Assert.assertTrue(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("read")).hasPermission("Read"));
Collections.emptySet(), ImmutableSet.of("read")).hasPermission("Read"));
Assert.assertFalse(new ZkBasicAuthPrincipal("name", "token", "password",
ComponentType.CONTROLLER.name(), RoleType.ADMIN.name(), ImmutableSet.of("myTable"),
ImmutableSet.of("read")).hasPermission("write"));
Collections.emptySet(), ImmutableSet.of("read")).hasPermission("write"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class UserConfig extends BaseJsonConfig {
public static final String ROLE_KEY = "role";
public static final String AUTH_TOKEN_KEY = "authToken";
public static final String TABLES_KEY = "tables";
public static final String EXCLUDE_TABLES_KEY = "excludeTables";
public static final String PERMISSIONS_KEY = "permissions";

@JsonPropertyDescription("The name of User")
Expand All @@ -52,6 +53,9 @@ public class UserConfig extends BaseJsonConfig {
@JsonPropertyDescription("The tables owned of User")
private List<String> _tables;

@JsonPropertyDescription("The tables excluded for User")
private List<String> _excludeTables;

@JsonPropertyDescription("The table permission of User")
private List<AccessType> _permissions;

Expand All @@ -61,6 +65,7 @@ public UserConfig(@JsonProperty(value = USERNAME_KEY, required = true) String us
@JsonProperty(value = COMPONET_KEY, required = true) String component,
@JsonProperty(value = ROLE_KEY, required = true) String role,
@JsonProperty(value = TABLES_KEY) @Nullable List<String> tableList,
@JsonProperty(value = EXCLUDE_TABLES_KEY) @Nullable List<String> excludeTableList,
@JsonProperty(value = PERMISSIONS_KEY) @Nullable List<AccessType> permissionList
) {
Preconditions.checkArgument(username != null, "'username' must be configured");
Expand All @@ -72,6 +77,7 @@ public UserConfig(@JsonProperty(value = USERNAME_KEY, required = true) String us
_componentType = ComponentType.valueOf(component.toUpperCase());
_roleType = RoleType.valueOf(role.toUpperCase());
_tables = tableList;
_excludeTables = excludeTableList;
_permissions = permissionList;
}

Expand All @@ -98,6 +104,11 @@ public List<String> getTables() {
return _tables;
}

@JsonProperty(EXCLUDE_TABLES_KEY)
public List<String> getExcludeTables() {
return _excludeTables;
}

@JsonProperty(PERMISSIONS_KEY)
public List<AccessType> getPermissios() {
return _permissions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class UserConfigBuilder {
private String _password;
private RoleType _roleType;
private List<String> _tableList;
private List<String> _excludeTableList;
private List<AccessType> _permissionList;

public UserConfigBuilder setComponentType(ComponentType componentType) {
Expand Down Expand Up @@ -58,13 +59,18 @@ public UserConfigBuilder setTableList(List<String> tableList) {
return this;
}

public UserConfigBuilder setExcludeTableList(List<String> excludeTableList) {
_excludeTableList = excludeTableList;
return this;
}

public UserConfigBuilder setPermissionList(List<AccessType> permissionList) {
_permissionList = permissionList;
return this;
}

public UserConfig build() {
return new UserConfig(_username, _password, _componentType.toString(), _roleType.toString(), _tableList,
_permissionList);
_excludeTableList, _permissionList);
}
}
Loading