Skip to content

Commit

Permalink
[Feature Request] Provide user access to all tables except tableX
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniilRoman committed Jan 18, 2025
1 parent eb9c759 commit 33db5bc
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 35 deletions.
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);
}
}

0 comments on commit 33db5bc

Please sign in to comment.