Add Row-Level Security (RLS) Support for ZooKeeper-Based Authentication#18051
Add Row-Level Security (RLS) Support for ZooKeeper-Based Authentication#18051NihalJain wants to merge 1 commit intoapache:masterfrom
Conversation
Fixes apache#17220 This commit extends Row-Level Security (RLS) functionality to ZooKeeper-based authentication (`ZkBasicAuthAccessControlFactory`), enabling dynamic user management with table-level filter controls via REST API. Previously, RLS filters were only supported with file-based `BasicAuth` configuration. ZK-based authentication passed empty RLS filter maps, preventing users from applying row-level restrictions when using ZooKeeper for user management. Changes: - Extended UserConfig to store RLS filters per table (`Map<String, List<String>>`) - Updated `AccessControlUserConfigUtils` to serialize/deserialize RLS filters to/from `ZNRecord` - Modified `BasicAuthUtils` to extract RLS filters from `UserConfig` and pass to `ZkBasicAuthPrincipal` - Implemented `getRowColFilters()` in `ZkBasicAuthAccessControlFactory` to return RLS filters - Updated `UserConfigBuilder` to support RLS filter configuration - Added comprehensive unit tests for `UserConfig`, `UserConfigBuilder`, and `AccessControlUserConfigUtils` - Added integration tests for ZkAuth RLS scenarios by extracting base class from existing `BasicAuth` tests Manual Testing: - Tested REST API create/update/get operations with RLS filters - Tested queries work as expected with rls for the ZK-based authentication API Example: ``` POST /users { "username": "user", "password": "secret", "component": "BROKER", "role": "USER", "tables": ["table1", "table2"], "permissions": ["READ"], "rlsFilters": { "table1": ["country='US'"], "table2": ["department='Engineering'", "level='Senior'"] } } ```
Tested REST API create/get/delete operations with RLS filters
Summary of the RLS tests performed with both Basic Auth and ZooKeeper-based Auth:Test Configuration
Tests Executed
Key Validations
Auth Modes Tested
PS: This was done with a bash script which I plan to contribute later with another PR |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #18051 +/- ##
============================================
+ Coverage 63.32% 63.35% +0.02%
+ Complexity 1543 1537 -6
============================================
Files 3200 3200
Lines 194209 194253 +44
Branches 29932 29937 +5
============================================
+ Hits 122986 123072 +86
+ Misses 61557 61517 -40
+ Partials 9666 9664 -2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hi team could you please provide some feedback |
| } | ||
|
|
||
| @Override | ||
| public TableRowColAccessResult getRowColFilters(RequesterIdentity requesterIdentity, String table) { |
There was a problem hiding this comment.
just for ease of reviewers: method is copy pasted from basic auth, will be refactored as common code with refactor task i will follow up with.
| .stream().map(x -> x.toString()) | ||
| .collect(Collectors.toSet()); | ||
| //todo: Handle RLS filters properly | ||
| // Extract RLS filters from UserConfig |
There was a problem hiding this comment.
just for ease of reviewers: here we simply pass rls for zk principal so that it can be applied during auth check
| List<String> excludeTableList = znRecord.getListField(UserConfig.EXCLUDE_TABLES_KEY); | ||
|
|
||
| List<String> permissionListFromZNRecord = znRecord.getListField(UserConfig.PERMISSIONS_KEY); | ||
| List<String> permissionListFromZNRecord = znRecord.getListField( |
There was a problem hiding this comment.
just for ease of reviewers: logic to persist rls in zk
| @JsonProperty(value = EXCLUDE_TABLES_KEY) @Nullable List<String> excludeTableList, | ||
| @JsonProperty(value = PERMISSIONS_KEY) @Nullable List<AccessType> permissionList) { | ||
| @JsonProperty(value = PERMISSIONS_KEY) @Nullable List<AccessType> permissionList, | ||
| @JsonProperty(value = RLS_FILTERS_KEY) @Nullable Map<String, List<String>> rlsFilters |
There was a problem hiding this comment.
just for ease of reviewers: changes for rest api
|
Hello everyone, just bumping this PR. Please let me know if you need me to make any changes or add more context. |
|
@9aman Could you help take a look at this PR? |
| if (rlsFiltersJson != null && !rlsFiltersJson.isEmpty()) { | ||
| try { | ||
| rlsFilters = JsonUtils.stringToObject( | ||
| rlsFiltersJson, new TypeReference<Map<String, List<String>>>() { |
| public TableRowColAccessResult getRowColFilters(RequesterIdentity requesterIdentity, String table) { | ||
| Optional<ZkBasicAuthPrincipal> principalOpt = getPrincipalAuth(requesterIdentity); | ||
|
|
||
| Preconditions.checkState(principalOpt.isPresent(), "Principal is not authorized"); |
There was a problem hiding this comment.
AccessControl.java:130 explicitly promises the method accepts table names with or without type.
Let's use
principal.hasTable(TableNameBuilder.extractRawTableName(table))
| UserConfig userConfig = AccessControlUserConfigUtils.fromZNRecord(znRecord); | ||
|
|
||
| Assert.assertNotNull(userConfig, "UserConfig should not be null"); | ||
| Assert.assertNull(userConfig.getRlsFilters(), "RLS filters should be null due to malformed JSON"); |
There was a problem hiding this comment.
@NihalJain Is this a desired behavior. A malformed json can allow the user to access everything within a table.
BasicAuthPrincipalUtils.extractBasicAuthPrincipals converts that null to Collections.emptyMap() and hence no filter is applied.
Fixes #17220
This commit extends Row-Level Security (RLS) functionality to ZooKeeper-based authentication (
ZkBasicAuthAccessControlFactory), enabling dynamic user management with table-level filter controls via REST API.Previously, RLS filters were only supported with file-based
BasicAuthconfiguration. ZK-based authentication passed empty RLS filter maps, preventing users from applying row-level restrictions when using ZooKeeper for user management.Changes:
Map<String, List<String>>)AccessControlUserConfigUtilsto serialize/deserialize RLS filters to/fromZNRecordBasicAuthUtilsto extract RLS filters fromUserConfigand pass toZkBasicAuthPrincipalgetRowColFilters()inZkBasicAuthAccessControlFactoryto return RLS filtersUserConfigBuilderto support RLS filter configurationUserConfig,UserConfigBuilder, andAccessControlUserConfigUtilsBasicAuthtestsManual Testing:
API Example: