This is an automated email from the ASF dual-hosted git repository. jackie pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push: new 0f2dcb770d refactor premission and access in controller rest api. (#13696) 0f2dcb770d is described below commit 0f2dcb770dca414b02dc4d495d4b4458fa2e91ec Author: Abhishek Sharma <abhishek.sha...@spothero.com> AuthorDate: Mon Aug 5 20:48:52 2024 -0400 refactor premission and access in controller rest api. (#13696) --- .../api/resources/PinotSchemaRestletResource.java | 40 ++++------------ .../api/resources/PinotTableRestletResource.java | 54 +++++++++++----------- .../controller/api/resources/ResourceUtils.java | 36 +++++++++++++++ 3 files changed, 70 insertions(+), 60 deletions(-) diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java index b372b1a633..876dd04be9 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSchemaRestletResource.java @@ -57,9 +57,7 @@ import org.apache.pinot.common.exception.TableNotFoundException; import org.apache.pinot.common.metrics.ControllerMeter; import org.apache.pinot.common.metrics.ControllerMetrics; import org.apache.pinot.common.utils.DatabaseUtils; -import org.apache.pinot.controller.api.access.AccessControl; import org.apache.pinot.controller.api.access.AccessControlFactory; -import org.apache.pinot.controller.api.access.AccessControlUtils; import org.apache.pinot.controller.api.access.AccessType; import org.apache.pinot.controller.api.access.Authenticate; import org.apache.pinot.controller.api.events.MetadataEventNotifierFactory; @@ -240,7 +238,8 @@ public class PinotSchemaRestletResource { validateSchemaName(schema); String schemaName = DatabaseUtils.translateTableName(schema.getSchemaName(), httpHeaders); schema.setSchemaName(schemaName); - checkPermissionAndAccess(schemaName, request, httpHeaders, AccessType.CREATE, Actions.Table.CREATE_SCHEMA); + ResourceUtils.checkPermissionAndAccess(schemaName, request, httpHeaders, + AccessType.CREATE, Actions.Table.CREATE_SCHEMA, _accessControlFactory, LOGGER); SuccessResponse successResponse = addSchema(schema, override, force); return new ConfigSuccessResponse(successResponse.getStatus(), schemaAndUnrecognizedProps.getRight()); } @@ -271,7 +270,8 @@ public class PinotSchemaRestletResource { validateSchemaName(schema); String schemaName = DatabaseUtils.translateTableName(schema.getSchemaName(), httpHeaders); schema.setSchemaName(schemaName); - checkPermissionAndAccess(schemaName, request, httpHeaders, AccessType.CREATE, Actions.Table.CREATE_SCHEMA); + ResourceUtils.checkPermissionAndAccess(schemaName, request, httpHeaders, + AccessType.CREATE, Actions.Table.CREATE_SCHEMA, _accessControlFactory, LOGGER); SuccessResponse successResponse = addSchema(schema, override, force); return new ConfigSuccessResponse(successResponse.getStatus(), schemaAndUnrecognizedProperties.getRight()); } @@ -296,7 +296,8 @@ public class PinotSchemaRestletResource { String schemaName = DatabaseUtils.translateTableName(schema.getSchemaName(), httpHeaders); schema.setSchemaName(schemaName); validateSchemaInternal(schema); - checkPermissionAndAccess(schemaName, request, httpHeaders, AccessType.READ, Actions.Table.VALIDATE_SCHEMA); + ResourceUtils.checkPermissionAndAccess(schemaName, request, httpHeaders, + AccessType.READ, Actions.Table.VALIDATE_SCHEMA, _accessControlFactory, LOGGER); ObjectNode response = schema.toJsonObject(); response.set("unrecognizedProperties", JsonUtils.objectToJsonNode(schemaAndUnrecognizedProps.getRight())); try { @@ -326,7 +327,8 @@ public class PinotSchemaRestletResource { String schemaName = DatabaseUtils.translateTableName(schema.getSchemaName(), httpHeaders); schema.setSchemaName(schemaName); validateSchemaInternal(schema); - checkPermissionAndAccess(schemaName, request, httpHeaders, AccessType.READ, Actions.Table.VALIDATE_SCHEMA); + ResourceUtils.checkPermissionAndAccess(schemaName, request, httpHeaders, + AccessType.READ, Actions.Table.VALIDATE_SCHEMA, _accessControlFactory, LOGGER); ObjectNode response = schema.toJsonObject(); response.set("unrecognizedProperties", JsonUtils.objectToJsonNode(schemaAndUnrecognizedProps.getRight())); try { @@ -528,30 +530,4 @@ public class PinotSchemaRestletResource { Response.Status.INTERNAL_SERVER_ERROR); } } - - /** - * Validates the permission and access for a given schema based on the request and HTTP headers. - * This method checks if the current user has the necessary permissions to perform an action on the specified schema. - * It utilizes the {@link AccessControl} mechanism to determine access rights - * and throws a {@link ControllerApplicationException} with a {@link Response.Status#FORBIDDEN} status - * if the access is denied. - * - * @param schemaName The name of the schema for which the permission and access are being checked. - * @param request The {@link Request} object containing information about the current request, - * used to extract the endpoint URL. - * @param httpHeaders The {@link HttpHeaders} associated with the request, - * used for authorization and other header-based access control checks. - * @param accessType The type of access being requested (e.g., CREATE, READ, UPDATE, DELETE). - * @param action The specific action being checked against the access control policies. - * @throws ControllerApplicationException if the user does not have the required permissions or access. - */ - private void checkPermissionAndAccess(String schemaName, Request request, HttpHeaders httpHeaders, - AccessType accessType, String action) { - String endpointUrl = request.getRequestURL().toString(); - AccessControl accessControl = _accessControlFactory.create(); - AccessControlUtils.validatePermission(schemaName, accessType, httpHeaders, endpointUrl, accessControl); - if (!accessControl.hasAccess(httpHeaders, TargetType.TABLE, schemaName, action)) { - throw new ControllerApplicationException(LOGGER, "Permission denied", Response.Status.FORBIDDEN); - } - } } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java index dab2bc4681..7a5fb1936b 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotTableRestletResource.java @@ -85,9 +85,7 @@ import org.apache.pinot.common.restlet.resources.ValidDocIdsType; import org.apache.pinot.common.utils.DatabaseUtils; import org.apache.pinot.common.utils.helix.HelixHelper; import org.apache.pinot.controller.ControllerConf; -import org.apache.pinot.controller.api.access.AccessControl; import org.apache.pinot.controller.api.access.AccessControlFactory; -import org.apache.pinot.controller.api.access.AccessControlUtils; import org.apache.pinot.controller.api.access.AccessType; import org.apache.pinot.controller.api.access.Authenticate; import org.apache.pinot.controller.api.exception.ControllerApplicationException; @@ -212,19 +210,11 @@ public class PinotTableRestletResource { tableNameWithType = DatabaseUtils.translateTableName(tableConfig.getTableName(), httpHeaders); tableConfig.setTableName(tableNameWithType); // Handle legacy config - SegmentsValidationAndRetentionConfig validationConfig = tableConfig.getValidationConfig(); - if (validationConfig.getSchemaName() != null) { - validationConfig.setSchemaName(DatabaseUtils.translateTableName(validationConfig.getSchemaName(), httpHeaders)); - } + handleLegacySchemaConfig(tableConfig, httpHeaders); // validate permission - String endpointUrl = request.getRequestURL().toString(); - AccessControl accessControl = _accessControlFactory.create(); - AccessControlUtils.validatePermission(tableNameWithType, AccessType.CREATE, httpHeaders, endpointUrl, - accessControl); - if (!accessControl.hasAccess(httpHeaders, TargetType.TABLE, tableNameWithType, Actions.Table.CREATE_TABLE)) { - throw new ControllerApplicationException(LOGGER, "Permission denied", Response.Status.FORBIDDEN); - } + ResourceUtils.checkPermissionAndAccess(tableNameWithType, request, httpHeaders, + AccessType.CREATE, Actions.Table.CREATE_TABLE, _accessControlFactory, LOGGER); Schema schema = _pinotHelixResourceManager.getSchemaForTableConfig(tableConfig); @@ -487,10 +477,7 @@ public class PinotTableRestletResource { tableNameWithType = DatabaseUtils.translateTableName(tableConfig.getTableName(), headers); tableConfig.setTableName(tableNameWithType); // Handle legacy config - SegmentsValidationAndRetentionConfig validationConfig = tableConfig.getValidationConfig(); - if (validationConfig.getSchemaName() != null) { - validationConfig.setSchemaName(DatabaseUtils.translateTableName(validationConfig.getSchemaName(), headers)); - } + handleLegacySchemaConfig(tableConfig, headers); String tableNameFromPath = DatabaseUtils.translateTableName( TableNameBuilder.forType(tableConfig.getTableType()).tableNameWithType(tableName), headers); if (!tableNameFromPath.equals(tableNameWithType)) { @@ -554,20 +541,13 @@ public class PinotTableRestletResource { TableConfig tableConfig = tableConfigAndUnrecognizedProperties.getLeft(); String tableNameWithType = DatabaseUtils.translateTableName(tableConfig.getTableName(), httpHeaders); tableConfig.setTableName(tableNameWithType); + // Handle legacy config - SegmentsValidationAndRetentionConfig validationConfig = tableConfig.getValidationConfig(); - if (validationConfig.getSchemaName() != null) { - validationConfig.setSchemaName(DatabaseUtils.translateTableName(validationConfig.getSchemaName(), httpHeaders)); - } + handleLegacySchemaConfig(tableConfig, httpHeaders); // validate permission - String endpointUrl = request.getRequestURL().toString(); - AccessControl accessControl = _accessControlFactory.create(); - AccessControlUtils.validatePermission(tableNameWithType, AccessType.READ, httpHeaders, endpointUrl, accessControl); - if (!accessControl.hasAccess(httpHeaders, TargetType.TABLE, tableNameWithType, - Actions.Table.VALIDATE_TABLE_CONFIGS)) { - throw new ControllerApplicationException(LOGGER, "Permission denied", Response.Status.FORBIDDEN); - } + ResourceUtils.checkPermissionAndAccess(tableNameWithType, request, httpHeaders, + AccessType.READ, Actions.Table.VALIDATE_TABLE_CONFIGS, _accessControlFactory, LOGGER); ObjectNode validationResponse = validateConfig(tableConfig, _pinotHelixResourceManager.getSchemaForTableConfig(tableConfig), typesToSkip); @@ -1270,4 +1250,22 @@ public class PinotTableRestletResource { return timeBoundaryMs; } + + /** + * Handles the legacy schema configuration for a given table configuration. + * This method updates the schema name in the validation configuration of the table config + * to ensure it is correctly translated based on the provided HTTP headers. + * This is necessary to maintain compatibility with older configurations that may not + * have the schema name properly set or formatted. + * + * @param tableConfig The {@link TableConfig} object containing the table configuration. + * @param httpHeaders The {@link HttpHeaders} object containing the HTTP headers, used to + * translate the schema name if necessary. + */ + private void handleLegacySchemaConfig(TableConfig tableConfig, HttpHeaders httpHeaders) { + SegmentsValidationAndRetentionConfig validationConfig = tableConfig.getValidationConfig(); + if (validationConfig.getSchemaName() != null) { + validationConfig.setSchemaName(DatabaseUtils.translateTableName(validationConfig.getSchemaName(), httpHeaders)); + } + } } diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ResourceUtils.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ResourceUtils.java index a1bb234ef2..ab091c8138 100644 --- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ResourceUtils.java +++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ResourceUtils.java @@ -20,11 +20,18 @@ package org.apache.pinot.controller.api.resources; import java.util.List; import javax.annotation.Nullable; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import org.apache.pinot.common.exception.TableNotFoundException; +import org.apache.pinot.controller.api.access.AccessControl; +import org.apache.pinot.controller.api.access.AccessControlFactory; +import org.apache.pinot.controller.api.access.AccessControlUtils; +import org.apache.pinot.controller.api.access.AccessType; import org.apache.pinot.controller.api.exception.ControllerApplicationException; import org.apache.pinot.controller.helix.core.PinotHelixResourceManager; +import org.apache.pinot.core.auth.TargetType; import org.apache.pinot.spi.config.table.TableType; +import org.glassfish.grizzly.http.server.Request; import org.slf4j.Logger; @@ -42,4 +49,33 @@ public class ResourceUtils { throw new ControllerApplicationException(logger, e.getMessage(), Response.Status.FORBIDDEN); } } + + /** + * Validates the permission and access for a specified type based on the incoming request and HTTP headers. + * This method ensures that the current user has the necessary permissions to perform the specified action + * on the given type. It leverages the {@link AccessControl} mechanism to assess access rights and + * throws a {@link ControllerApplicationException} with a {@link Response.Status#FORBIDDEN} status code + * if access is denied. This is crucial for enforcing security and access control within the application. + * + * @param typeName The name of the type for which permission and access are being verified. + * @param request The {@link Request} object containing details about the current request, utilized + * to extract the endpoint URL for access validation. + * @param httpHeaders The {@link HttpHeaders} associated with the request, used for authorization + * and other header-based access control checks. + * @param accessType The type of access being requested (e.g., CREATE, READ, UPDATE, DELETE). + * @param action The specific action being checked against the access control policies. + * @param accessControlFactory The {@link AccessControlFactory} used to create an {@link AccessControl} instance + * for validating permissions. + * @param logger The {@link Logger} used for logging any access control related messages. + * @throws ControllerApplicationException if the user lacks the required permissions or access. + */ + public static void checkPermissionAndAccess(String typeName, Request request, HttpHeaders httpHeaders, + AccessType accessType, String action, AccessControlFactory accessControlFactory, Logger logger) { + String endpointUrl = request.getRequestURL().toString(); + AccessControl accessControl = accessControlFactory.create(); + AccessControlUtils.validatePermission(typeName, accessType, httpHeaders, endpointUrl, accessControl); + if (!accessControl.hasAccess(httpHeaders, TargetType.TABLE, typeName, action)) { + throw new ControllerApplicationException(logger, "Permission denied", Response.Status.FORBIDDEN); + } + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org