bharos commented on code in PR #9988:
URL: https://github.com/apache/gravitino/pull/9988#discussion_r2821624016


##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java:
##########
@@ -122,13 +123,39 @@ public void dropTable(
   @Override
   public LoadTableResponse loadTable(
       IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    String catalogName = context.catalogName();
+
+    // Per Iceberg REST spec, /tables/ endpoint should only serve tables, not 
views.
+    // Check if the identifier is a view and throw NoSuchTableException to 
trigger
+    // Spark's fallback logic to use /views/ endpoint instead.
+    if 
(icebergCatalogWrapperManager.getCatalogWrapper(catalogName).viewExists(tableIdentifier))
 {

Review Comment:
   @roryqi Actually, checking tableExists seems hard.
   It then means, a user who doesn't have privilege to even check existence of 
a table will get 404 (when they should get 403)
   
   So I think it's better to check viewExists() then return 404, so that users 
who have no permissions will get 403 for non-existent tables as well



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java:
##########
@@ -122,13 +123,39 @@ public void dropTable(
   @Override
   public LoadTableResponse loadTable(
       IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    String catalogName = context.catalogName();
+
+    // Per Iceberg REST spec, /tables/ endpoint should only serve tables, not 
views.

Review Comment:
   Done
   
   This required a refactor, to be able to access the catalogWrapperManager in 
LoadTableAuthzHandler.
   For this, I had to inject catalogWrapperManager into IcebergRESTServerContext
   
   But catalogWrapperManager and IcebergRESTServerContext had a circular 
depenency, so I had to pass  auxMode, metalakeName to the catalogWrapperManager 
to avoid depending on the serverContext
   
   Hope this is ok.. ?



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java:
##########
@@ -122,13 +122,15 @@ public void dropTable(
   @Override
   public LoadTableResponse loadTable(
       IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    String catalogName = context.catalogName();

Review Comment:
   done



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java:
##########
@@ -122,13 +123,39 @@ public void dropTable(
   @Override
   public LoadTableResponse loadTable(
       IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    String catalogName = context.catalogName();
+
+    // Per Iceberg REST spec, /tables/ endpoint should only serve tables, not 
views.
+    // Check if the identifier is a view and throw NoSuchTableException to 
trigger
+    // Spark's fallback logic to use /views/ endpoint instead.
+    if 
(icebergCatalogWrapperManager.getCatalogWrapper(catalogName).viewExists(tableIdentifier))
 {

Review Comment:
   done



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/server/web/filter/IcebergMetadataAuthorizationMethodInterceptor.java:
##########
@@ -80,6 +80,10 @@ protected Map<Entity.EntityType, NameIdentifier> 
extractNameIdentifierFromParame
               NameIdentifierUtil.ofTable(
                   metalakeName, catalog, schema, 
RESTUtil.decodeString(value)));
           break;
+        case VIEW:
+          nameIdentifierMap.put(
+              EntityType.VIEW, NameIdentifierUtil.ofView(metalakeName, 
catalog, schema, value));

Review Comment:
   Decoded the table/view name correctly



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergViewOperations.java:
##########
@@ -89,6 +105,13 @@ public Response listView(
                 new IcebergRequestContext(httpServletRequest(), catalogName);
             ListTablesResponse listTablesResponse =

Review Comment:
   I think so, seems like we don't have view specific response ..



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/RESTService.java:
##########
@@ -113,6 +113,7 @@ private void initServer(IcebergConfig icebergConfig) {
     }
     IcebergTableEventDispatcher icebergTableEventDispatcher =
         new IcebergTableEventDispatcher(icebergTableOperationDispatcher, 
eventBus, metalakeName);
+

Review Comment:
   done



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergViewOperations.java:
##########
@@ -131,10 +161,17 @@ public Response createView(
   @Produces(MediaType.APPLICATION_JSON)
   @Timed(name = "load-view." + MetricNames.HTTP_PROCESS_DURATION, absolute = 
true)
   @ResponseMetered(name = "load-view", absolute = true)
+  @AuthorizationExpression(
+      expression =
+          "ANY(OWNER, METALAKE, CATALOG) || "
+              + "SCHEMA_OWNER_WITH_USE_CATALOG || "
+              + "ANY_USE_CATALOG && ANY_USE_SCHEMA && (VIEW::OWNER || 
ANY_SELECT_VIEW)",

Review Comment:
   The tests were passing without it.
   But looking at the code, I am not 100% sure, but I do see in some places it 
calls viewExists in createView
   like here : 
https://github.com/apache/iceberg/blob/main/core/src/main/java/org/apache/iceberg/jdbc/JdbcViewOperations.java#L191C18-L191C28
   
   So I think it should be added



##########
iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/server/web/filter/LoadTableAuthzHandler.java:
##########
@@ -58,7 +65,7 @@ public void process(Map<EntityType, NameIdentifier> 
nameIdentifierMap) {
       IcebergAuthorizationMetadata icebergMetadata =
           parameter.getAnnotation(IcebergAuthorizationMetadata.class);
       if (icebergMetadata != null && icebergMetadata.type() == 
RequestType.LOAD_TABLE) {
-        tableName = String.valueOf(args[i]);
+        tableName = RESTUtil.decodeString(String.valueOf(args[i]));

Review Comment:
   I tried to change it now but it was hard to do it in a generic way.
   
   Namespace parameters require RESTUtil.decodeNamespace()(special parsing) vs 
table names need RESTUtil.decodeString(). Decoding in the handler keeps the 
logic simple and localized - each handler decodes only what it needs with the 
appropriate method. 
   
   Maybe we can revisit this in future PR if you have any idea ?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to