lsherwin10 opened a new issue, #18662:
URL: https://github.com/apache/iceberg/issues/18662

   ### Apache Iceberg version
   
   1.10.1
   
   ### Query engine
   
   Spark
   
   ### Please describe the bug 🐞
   
   In `RESTSessionCatalog.Builder.replaceTransaction()` ([lines 
828–832](https://github.com/apache/iceberg/blob/apache-iceberg-1.10.1/core/src/main/java/org/apache/iceberg/rest/RESTSessionCatalog.java#L828-L832)),
 the client unconditionally checks `if (viewExists(context, ident))` before 
staging a replacement table:
   
   ```java
   @Override
   public Transaction replaceTransaction() {
     Endpoint.check(endpoints, Endpoint.V1_UPDATE_TABLE);
     if (viewExists(context, ident)) {
       throw new AlreadyExistsException("View with same name already exists: 
%s", ident);
     }
     ...
   ```
   
   When connecting to a REST catalog with table-only permissions where view 
endpoints are supported, `/views/{view}` returns `HTTP 403 Forbidden`. Because 
`viewExists()` does not catch `ForbiddenException`, `CREATE OR REPLACE TABLE` 
fails even though the caller has full table rights:
   
   ```text
   26/10/26 22:46:52 ERROR SparkSQLDriver: Failed in [create or replace table 
test_table (id INT, data STRING)]
   org.apache.iceberg.exceptions.ForbiddenException: Forbidden: Forbidden
           at 
org.apache.iceberg.rest.ErrorHandlers$DefaultErrorHandler.accept(ErrorHandlers.java:238)
           at 
org.apache.iceberg.rest.ErrorHandlers$ViewErrorHandler.accept(ErrorHandlers.java:168)
           at 
org.apache.iceberg.rest.ErrorHandlers$ViewErrorHandler.accept(ErrorHandlers.java:152)
           at 
org.apache.iceberg.rest.HTTPClient.throwFailure(HTTPClient.java:240)
           at org.apache.iceberg.rest.HTTPClient.execute(HTTPClient.java:336)
           at org.apache.iceberg.rest.HTTPClient.execute(HTTPClient.java:297)
           at 
org.apache.iceberg.rest.BaseHTTPClient.head(BaseHTTPClient.java:45)
           at 
org.apache.iceberg.rest.RESTSessionCatalog.viewExists(RESTSessionCatalog.java:1112)
           at 
org.apache.iceberg.rest.RESTSessionCatalog$Builder.replaceTransaction(RESTSessionCatalog.java:830)
           at 
org.apache.iceberg.rest.RESTSessionCatalog$Builder.createOrReplaceTransaction(RESTSessionCatalog.java:899)
           at 
org.apache.iceberg.CachingCatalog$CachingTableBuilder.createOrReplaceTransaction(CachingCatalog.java:302)
           at 
org.apache.iceberg.spark.SparkCatalog.stageCreateOrReplace(SparkCatalog.java:303)
           at 
org.apache.spark.sql.connector.catalog.StagingTableCatalog.stageCreateOrReplace(StagingTableCatalog.java:188)
           at 
org.apache.spark.sql.execution.datasources.v2.AtomicReplaceTableExec.run(ReplaceTableExec.scala:75)
           at 
org.apache.spark.sql.execution.datasources.v2.V2CommandExec.result$lzycompute(V2CommandExec.scala:43)
           at 
org.apache.spark.sql.execution.datasources.v2.V2CommandExec.result(V2CommandExec.scala:43)
           at 
org.apache.spark.sql.execution.datasources.v2.V2CommandExec.executeCollect(V2CommandExec.scala:49)
           at 
org.apache.spark.sql.execution.QueryExecution$$anonfun$eagerlyExecuteCommands$1.$anonfun$applyOrElse$1(QueryExecution.scala:107)
           at 
org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$6(SQLExecution.scala:125)
           at 
org.apache.spark.sql.execution.SQLExecution$.withSQLConfPropagated(SQLExecution.scala:201)
           at 
org.apache.spark.sql.execution.SQLExecution$.$anonfun$withNewExecutionId$1(SQLExecution.scala:108)
           at 
org.apache.spark.sql.SparkSession.withActive(SparkSession.scala:900)
   ```
   
   Additionally, configuring `spark.sql.catalog.<name>.view-endpoints-supported 
= false` has no effect because `RESTSessionCatalog.initialize()` only checks 
this property when `config.endpoints().isEmpty()`. If the server advertises 
view endpoints in `/v1/config`, the client setting is ignored.
   
   #### What to expect
   - `CREATE OR REPLACE TABLE` should succeed when the user has table 
permissions, without requiring view permissions (matching 
`createTransaction()`, which does not call `viewExists()`).
   - Setting `view-endpoints-supported = false` should allow clients to disable 
view endpoints even if the server advertises them.
   
   #### How to reproduce
   1. Configure an Iceberg REST catalog where view endpoints are exposed and 
perform auth checks, the credentials grant access to tables, but deny access to 
views.
   2. Run:
      ```sql
      CREATE TABLE cat.db.orders (id INT) USING iceberg;
      CREATE OR REPLACE TABLE cat.db.orders (id INT, status STRING) USING 
iceberg;
      ```
   3. `CREATE TABLE` succeeds, but `CREATE OR REPLACE TABLE` fails with 
`ForbiddenException: 403`.
   
   ### Willingness to contribute
   
   - [ ] I can contribute a fix for this bug independently
   - [ ] I would be willing to contribute a fix for this bug with guidance from 
the Iceberg community
   - [ ] I cannot contribute a fix for this bug at this time


-- 
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]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to