This is an automated email from the ASF dual-hosted git repository.

gianm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 58ccdfa1dba feat: Directly produce Resource in NamedSchema. (#20254)
58ccdfa1dba is described below

commit 58ccdfa1dba22777917bbe960f63b9d4be4a0315
Author: Gian Merlino <[email protected]>
AuthorDate: Fri Sep 4 15:16:42 2026 -0700

    feat: Directly produce Resource in NamedSchema. (#20254)
    
    This patch is a follow-up to #20075 that changes things such that
    NamedSchemas directly produce the Resources for authorization, rather
    than relying on consumers to construct Resources themselves. This
    simplifies the code and also makes it possible for NamedSchema to be
    more flexible in the kinds of Resources they return. (They don't all
    need to be the same type, or have names match the table.)
---
 .../druid/sql/calcite/planner/PlannerContext.java  |  11 +-
 .../planner/SqlResourceCollectorShuttle.java       |   8 +-
 .../druid/sql/calcite/schema/DruidSchema.java      |   4 +-
 .../sql/calcite/schema/DruidSchemaCatalog.java     |  15 ++-
 .../schema/DruidSchemaCatalogProviderImpl.java     |   8 +-
 .../sql/calcite/schema/InformationSchema.java      |  15 +--
 .../druid/sql/calcite/schema/NamedDruidSchema.java |   5 +-
 .../sql/calcite/schema/NamedLookupSchema.java      |  11 ++
 .../druid/sql/calcite/schema/NamedSchema.java      |  11 +-
 .../sql/calcite/schema/NamedSystemSchema.java      |   5 +-
 .../druid/sql/calcite/schema/NamedViewSchema.java  |   5 +-
 .../druid/sql/calcite/schema/SchemaUtils.java      |  55 +++++++---
 .../druid/sql/calcite/schema/SystemSchema.java     |   8 +-
 .../druid/sql/calcite/schema/ViewSchema.java       |   2 +-
 .../calcite/planner/CalcitePlannerModuleTest.java  |   7 +-
 .../sql/calcite/schema/NamedSystemSchemaTest.java  |   5 +-
 .../druid/sql/calcite/schema/SchemaUtilsTest.java  | 114 +++++++++++++++++++++
 17 files changed, 229 insertions(+), 60 deletions(-)

diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java
index fc03979d761..e9826af5dd4 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/planner/PlannerContext.java
@@ -52,8 +52,8 @@ import org.apache.druid.segment.join.JoinableFactoryWrapper;
 import org.apache.druid.server.lookup.cache.LookupLoadingSpec;
 import org.apache.druid.server.security.AuthenticationResult;
 import org.apache.druid.server.security.AuthorizationResult;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceAction;
-import org.apache.druid.server.security.ResourceType;
 import org.apache.druid.sql.calcite.expression.SqlOperatorConversion;
 import 
org.apache.druid.sql.calcite.expression.builtin.QueryLookupOperatorConversion;
 import org.apache.druid.sql.calcite.rel.VirtualColumnRegistry;
@@ -326,13 +326,14 @@ public class PlannerContext
   }
 
   /**
-   * Returns the {@link ResourceType} string for a particular resource (e.g. 
table, view) located in a
-   * particular schema. If null, there is no authorization associated with the 
named resource.
+   * Returns the {@link Resource} to authorize against for a particular 
resource (e.g. table, view) located in a
+   * particular schema. If null, there is no authorization associated with the 
named resource (all authenticated
+   * users may access it).
    */
   @Nullable
-  public String getSchemaResourceType(String schema, String resourceName)
+  public Resource getSchemaResource(String schema, String resourceName)
   {
-    return rootSchema.getResourceType(schema, resourceName);
+    return rootSchema.getResource(schema, resourceName);
   }
 
   /**
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java
 
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java
index e2c5739dae8..279ac7476a7 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/planner/SqlResourceCollectorShuttle.java
@@ -46,7 +46,7 @@ import java.util.Set;
  * <p>First, look for {@link SqlIdentifier} which correspond to a {@link 
IdentifierNamespace}, where
  * {@link SqlValidatorNamespace} is calcite-speak for sources of data and 
{@link IdentifierNamespace} specifically are
  * namespaces which are identified by a single variable, e.g. table names. 
These are translated into resources
- * using {@link PlannerContext#getSchemaResourceType}.
+ * using {@link PlannerContext#getSchemaResource}.
  *
  * <p>Second, look for {@link AuthorizableOperator} and call {@link 
AuthorizableOperator#computeResources}.
  *
@@ -100,9 +100,9 @@ public class SqlResourceCollectorShuttle extends SqlShuttle
             plannerContext.addLookupToLoad(resourceName);
           }
 
-          final String resourceType = 
plannerContext.getSchemaResourceType(schema, resourceName);
-          if (resourceType != null) {
-            resourceActions.add(new ResourceAction(new Resource(resourceName, 
resourceType), Action.READ));
+          final Resource resource = plannerContext.getSchemaResource(schema, 
resourceName);
+          if (resource != null) {
+            resourceActions.add(new ResourceAction(resource, Action.READ));
           }
         } else if (qualifiedNameParts.size() > 2) {
           // Don't expect to see more than 2 names (catalog?).
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchema.java
index 6048acf043f..a76e64c68ca 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchema.java
@@ -64,7 +64,7 @@ public class DruidSchema extends AbstractTableSchema
   public Table getTable(String name)
   {
     if (authorizeTableVisibility
-        && !SchemaUtils.isTableVisible(authorizerMapper, authenticationResult, 
name, _ -> ResourceType.DATASOURCE)) {
+        && !SchemaUtils.isTableVisible(authorizerMapper, authenticationResult, 
name, ResourceType.DATASOURCE)) {
       // Do not return tables that are not supposed to be visible in this 
schema.
       return null;
     }
@@ -97,7 +97,7 @@ public class DruidSchema extends AbstractTableSchema
           authorizerMapper,
           authenticationResult,
           allTableNames,
-          _ -> ResourceType.DATASOURCE
+          ResourceType.DATASOURCE
       );
     } else {
       return allTableNames;
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java
index 3b169b7d098..cc13c452fe9 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalog.java
@@ -21,6 +21,7 @@ package org.apache.druid.sql.calcite.schema;
 
 import com.google.common.base.Preconditions;
 import org.apache.calcite.schema.SchemaPlus;
+import org.apache.druid.error.DruidException;
 import org.apache.druid.server.security.Resource;
 
 import javax.annotation.Nullable;
@@ -83,13 +84,21 @@ public class DruidSchemaCatalog
 
   /**
    * Given the name of a {@link NamedSchema} and the name of a table or 
function that belongs to that schema, return
-   * the appropriate value to use for {@link Resource#getType()} during 
authorization
+   * the {@link Resource} to authorize against. Null means no authorization is 
needed.
    */
   @Nullable
-  public String getResourceType(String schema, String resourceName)
+  public Resource getResource(String schema, String resourceName)
   {
     final NamedSchema namedSchema = namedSchemas.get(schema);
-    return namedSchema == null ? null : 
namedSchema.getSchemaResourceType(resourceName);
+    if (namedSchema != null) {
+      return namedSchema.getSchemaResource(resourceName);
+    } else if (InformationSchema.INFORMATION_SCHEMA_NAME.equals(schema)) {
+      // Everyone can read INFORMATION_SCHEMA.
+      return null;
+    } else {
+      // We shouldn't need to get a Resource for a schema that doesn't exist.
+      throw DruidException.defensive("No schema named[%s]", schema);
+    }
   }
 
   @Override
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalogProviderImpl.java
 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalogProviderImpl.java
index a88702128a1..a46813815ff 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalogProviderImpl.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/DruidSchemaCatalogProviderImpl.java
@@ -36,8 +36,6 @@ import java.util.TreeMap;
 @LazySingleton
 public class DruidSchemaCatalogProviderImpl implements 
DruidSchemaCatalogProvider
 {
-  private static final String INFORMATION_SCHEMA_NAME = "INFORMATION_SCHEMA";
-
   private final Set<NamedSchema> namedSchemas;
   private final Set<SchemaProvider> schemaProviders;
   private final DruidOperatorTable operatorTable;
@@ -82,8 +80,8 @@ public class DruidSchemaCatalogProviderImpl implements 
DruidSchemaCatalogProvide
       }
     }
 
-    if (allSchemas.containsKey(INFORMATION_SCHEMA_NAME)) {
-      throw new ISE("Cannot have schema named[%s]", INFORMATION_SCHEMA_NAME);
+    if (allSchemas.containsKey(InformationSchema.INFORMATION_SCHEMA_NAME)) {
+      throw new ISE("Cannot have schema named[%s]", 
InformationSchema.INFORMATION_SCHEMA_NAME);
     }
 
     // Add allSchemas to the rootSchema.
@@ -95,7 +93,7 @@ public class DruidSchemaCatalogProviderImpl implements 
DruidSchemaCatalogProvide
 
     // One more schema to add: INFORMATION_SCHEMA.
     rootSchema.add(
-        INFORMATION_SCHEMA_NAME,
+        InformationSchema.INFORMATION_SCHEMA_NAME,
         new InformationSchema(
             schemaCatalog,
             operatorTable,
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java
index e4109a6a4b0..dcf02d7e860 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/InformationSchema.java
@@ -45,6 +45,7 @@ import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.druid.java.util.emitter.EmittingLogger;
 import org.apache.druid.server.security.AuthenticationResult;
 import org.apache.druid.server.security.AuthorizerMapper;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.sql.calcite.planner.Calcites;
 import org.apache.druid.sql.calcite.planner.DruidOperatorTable;
 import org.apache.druid.sql.calcite.planner.DruidTypeSystem;
@@ -171,13 +172,13 @@ public class InformationSchema extends AbstractSchema
     return tableMap;
   }
 
-  private Set<String> getVisibleNames(final Iterable<String> allNames, final 
Function<String, String> resourceTypeFn)
+  private Set<String> getVisibleNames(final Iterable<String> allNames, final 
Function<String, Resource> resourceFn)
   {
-    return SchemaUtils.filterVisibleTables(
+    return SchemaUtils.filterVisibleResources(
         authorizerMapper,
         authenticationResult,
         allNames,
-        resourceTypeFn
+        resourceFn
     );
   }
 
@@ -249,11 +250,11 @@ public class InformationSchema extends AbstractSchema
                   final SchemaPlus subSchema = 
rootSchema.getSubSchema(schemaName);
                   final Set<String> tableNames = getVisibleNames(
                       subSchema.tables().getNames(LikePattern.any()),
-                      tableName -> 
rootSchema.getResourceType(subSchema.getName(), tableName)
+                      tableName -> rootSchema.getResource(subSchema.getName(), 
tableName)
                   );
                   final Set<String> functionNames = getVisibleNames(
                       subSchema.getFunctionNames(),
-                      tableName -> 
rootSchema.getResourceType(subSchema.getName(), tableName)
+                      tableName -> rootSchema.getResource(subSchema.getName(), 
tableName)
                   );
 
                   return Iterables.filter(
@@ -349,11 +350,11 @@ public class InformationSchema extends AbstractSchema
                   final RelDataTypeFactory typeFactory = root.getTypeFactory();
                   final Set<String> tableNames = getVisibleNames(
                       subSchema.tables().getNames(LikePattern.any()),
-                      tableName -> 
rootSchema.getResourceType(subSchema.getName(), tableName)
+                      tableName -> rootSchema.getResource(subSchema.getName(), 
tableName)
                   );
                   final Set<String> functionNames = getVisibleNames(
                       subSchema.getFunctionNames(),
-                      tableName -> 
rootSchema.getResourceType(subSchema.getName(), tableName)
+                      tableName -> rootSchema.getResource(subSchema.getName(), 
tableName)
                   );
 
                   return Iterables.concat(
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java
index bc0a791bbd9..bc6fa67bf13 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedDruidSchema.java
@@ -20,6 +20,7 @@
 package org.apache.druid.sql.calcite.schema;
 
 import org.apache.calcite.schema.Schema;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceType;
 
 /**
@@ -43,9 +44,9 @@ public class NamedDruidSchema implements NamedSchema
   }
 
   @Override
-  public String getSchemaResourceType(String resourceName)
+  public Resource getSchemaResource(String resourceName)
   {
-    return ResourceType.DATASOURCE;
+    return new Resource(resourceName, ResourceType.DATASOURCE);
   }
 
   @Override
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java
index e99c2ffab90..120a0e67458 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedLookupSchema.java
@@ -22,6 +22,9 @@ package org.apache.druid.sql.calcite.schema;
 import com.google.inject.Inject;
 import org.apache.calcite.schema.Schema;
 import org.apache.druid.guice.LazySingleton;
+import org.apache.druid.server.security.Resource;
+
+import javax.annotation.Nullable;
 
 /**
  * The schema for Druid lookup tables to be accessible via SQL.
@@ -45,6 +48,14 @@ public class NamedLookupSchema implements NamedSchema
     return NAME;
   }
 
+  @Nullable
+  @Override
+  public Resource getSchemaResource(String resourceName)
+  {
+    // No authorization for lookups.
+    return null;
+  }
+
   @Override
   public Schema getSchema()
   {
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java
index da951aa6273..a08bf1a7242 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSchema.java
@@ -20,6 +20,7 @@
 package org.apache.druid.sql.calcite.schema;
 
 import org.apache.calcite.schema.Schema;
+import org.apache.druid.server.security.Resource;
 
 import javax.annotation.Nullable;
 
@@ -35,15 +36,11 @@ public interface NamedSchema
   String getSchemaName();
 
   /**
-   * For a given name of a table, function, etc of this schema, return the 
value most appropriate to use for
-   * {@link org.apache.druid.server.security.Resource#getType()} for the 
resource, used during authorization. If this
-   * method returns null then the resource does not need any authorization.
+   * For a given name of a table, function, etc of this schema, return {@link 
Resource} to use
+   * during authorization. If this method returns null then the resource does 
not need any authorization.
    */
   @Nullable
-  default String getSchemaResourceType(String resourceName)
-  {
-    return null;
-  }
+  Resource getSchemaResource(String resourceName);
 
   /**
    * @return The Schema that Calcite should use.
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java
index be206b9caa2..cd13ffc5e53 100644
--- 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java
+++ 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedSystemSchema.java
@@ -20,6 +20,7 @@
 package org.apache.druid.sql.calcite.schema;
 
 import org.apache.calcite.schema.Schema;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceType;
 import org.apache.druid.sql.calcite.planner.PlannerConfig;
 
@@ -55,10 +56,10 @@ public class NamedSystemSchema implements NamedSchema
 
   @Nullable
   @Override
-  public String getSchemaResourceType(String resourceName)
+  public Resource getSchemaResource(String resourceName)
   {
     if (plannerConfig.isAuthorizeSystemTablesDirectly()) {
-      return ResourceType.SYSTEM_TABLE;
+      return new Resource(resourceName, ResourceType.SYSTEM_TABLE);
     }
     return null;
   }
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java
index 826d25ec248..65b9a2e3372 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/NamedViewSchema.java
@@ -20,6 +20,7 @@
 package org.apache.druid.sql.calcite.schema;
 
 import org.apache.calcite.schema.Schema;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceType;
 
 public class NamedViewSchema implements NamedSchema
@@ -39,9 +40,9 @@ public class NamedViewSchema implements NamedSchema
   }
 
   @Override
-  public String getSchemaResourceType(String resourceName)
+  public Resource getSchemaResource(String resourceName)
   {
-    return ResourceType.VIEW;
+    return new Resource(resourceName, ResourceType.VIEW);
   }
 
   @Override
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SchemaUtils.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SchemaUtils.java
index 6e8202c8b06..4af7ca744bf 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SchemaUtils.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SchemaUtils.java
@@ -19,6 +19,7 @@
 
 package org.apache.druid.sql.calcite.schema;
 
+import org.apache.druid.error.DruidException;
 import org.apache.druid.server.security.Action;
 import org.apache.druid.server.security.AuthenticationResult;
 import org.apache.druid.server.security.AuthorizationUtils;
@@ -26,8 +27,10 @@ import org.apache.druid.server.security.AuthorizerMapper;
 import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceAction;
 
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -38,45 +41,73 @@ public class SchemaUtils
     // No instantiation.
   }
 
+  /**
+   * Returns whether a given table with resource type {@code resourceType} 
should be visible.
+   */
   public static boolean isTableVisible(
       final AuthorizerMapper authorizerMapper,
       final AuthenticationResult authenticationResult,
       final String tableName,
-      final Function<String, String> resourceTypeFn
+      final String resourceType
   )
   {
-    return !filterVisibleTables(authorizerMapper, authenticationResult, 
Set.of(tableName), resourceTypeFn).isEmpty();
+    return !filterVisibleTables(authorizerMapper, authenticationResult, 
Set.of(tableName), resourceType).isEmpty();
   }
 
+  /**
+   * Returns the set of visible table names, given tables with resource type 
{@code resourceType}.
+   */
   public static Set<String> filterVisibleTables(
       final AuthorizerMapper authorizerMapper,
       final AuthenticationResult authenticationResult,
       final Iterable<String> tableNames,
-      final Function<String, String> resourceTypeFn
+      final String resourceType
+  )
+  {
+    if (resourceType == null) {
+      throw DruidException.defensive("Null resource type not expected");
+    }
+
+    return filterVisibleResources(
+        authorizerMapper,
+        authenticationResult,
+        tableNames,
+        name -> new Resource(name, resourceType)
+    );
+  }
+
+  /**
+   * Like {@link #filterVisibleTables}, but each name is mapped to the {@link 
Resource} to authorize against, which
+   * need not be named after the object itself. A null resource means the name 
does not need authorization.
+   */
+  public static Set<String> filterVisibleResources(
+      final AuthorizerMapper authorizerMapper,
+      final AuthenticationResult authenticationResult,
+      final Iterable<String> names,
+      final Function<String, Resource> resourceFn
   )
   {
     final Set<String> visibleNames = new LinkedHashSet<>();
-    final Set<Resource> authorizableResources = new LinkedHashSet<>();
+    final Map<Resource, Set<String>> namesByResource = new LinkedHashMap<>();
 
-    for (final String tableName : tableNames) {
-      final String resourceType = resourceTypeFn.apply(tableName);
-      if (resourceType == null) {
-        // No ResourceType means this name does not need authorization. It's 
always visible.
-        visibleNames.add(tableName);
+    for (final String name : names) {
+      final Resource resource = resourceFn.apply(name);
+      if (resource == null) {
+        visibleNames.add(name);
       } else {
-        authorizableResources.add(new Resource(tableName, resourceType));
+        namesByResource.computeIfAbsent(resource, _ -> new 
LinkedHashSet<>()).add(name);
       }
     }
 
     final Iterable<Resource> authorizedResources = 
AuthorizationUtils.filterAuthorizedResources(
         authenticationResult,
-        authorizableResources,
+        namesByResource.keySet(),
         resource -> List.of(new ResourceAction(resource, Action.READ)),
         authorizerMapper
     );
 
     for (final Resource resource : authorizedResources) {
-      visibleNames.add(resource.getName());
+      visibleNames.addAll(namesByResource.get(resource));
     }
 
     return visibleNames;
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
index 8ccbcf19c81..885fc1ca352 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/SystemSchema.java
@@ -345,12 +345,12 @@ public class SystemSchema extends AbstractTableSchema
   @Override
   public Set<String> getTableNames()
   {
-    if (plannerConfig.isAuthorizeTableVisibility()) {
+    if (plannerConfig.isAuthorizeTableVisibility() && 
plannerConfig.isAuthorizeSystemTablesDirectly()) {
       return SchemaUtils.filterVisibleTables(
           authorizerMapper,
           authenticationResult,
           allTableNames,
-          _ -> plannerConfig.isAuthorizeSystemTablesDirectly() ? 
ResourceType.SYSTEM_TABLE : null
+          ResourceType.SYSTEM_TABLE
       );
     } else {
       // sys table authorization is not enabled, so all sys tables are visible 
to all users.
@@ -366,12 +366,12 @@ public class SystemSchema extends AbstractTableSchema
     if (!allTableNames.contains(sysTableName)) {
       // Short circuit that hides sys.queries if it is disabled server-wide.
       return false;
-    } else if (plannerConfig.isAuthorizeTableVisibility()) {
+    } else if (plannerConfig.isAuthorizeTableVisibility() && 
plannerConfig.isAuthorizeSystemTablesDirectly()) {
       return SchemaUtils.isTableVisible(
           authorizerMapper,
           authenticationResult,
           sysTableName,
-          _ -> plannerConfig.isAuthorizeSystemTablesDirectly() ? 
ResourceType.SYSTEM_TABLE : null
+          ResourceType.SYSTEM_TABLE
       );
     } else {
       // sys table authorization is not enabled, so all sys tables are visible 
to all users.
diff --git 
a/sql/src/main/java/org/apache/druid/sql/calcite/schema/ViewSchema.java 
b/sql/src/main/java/org/apache/druid/sql/calcite/schema/ViewSchema.java
index 9cbf0ac8e2e..9f4d77b6299 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/schema/ViewSchema.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/schema/ViewSchema.java
@@ -72,7 +72,7 @@ public class ViewSchema extends AbstractSchema
           authorizerMapper,
           authenticationResult,
           viewsMap.keySet(),
-          _ -> ResourceType.VIEW
+          ResourceType.VIEW
       );
     } else {
       visibleViews = viewsMap.keySet();
diff --git 
a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java
 
b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java
index 364881135ea..3808b18d0f4 100644
--- 
a/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java
+++ 
b/sql/src/test/java/org/apache/druid/sql/calcite/planner/CalcitePlannerModuleTest.java
@@ -42,6 +42,7 @@ import org.apache.druid.math.expr.ExprMacroTable;
 import org.apache.druid.segment.join.JoinableFactoryWrapper;
 import org.apache.druid.server.QueryLifecycleFactory;
 import org.apache.druid.server.security.AuthorizerMapper;
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceType;
 import org.apache.druid.sql.SqlStatementFactory;
 import org.apache.druid.sql.calcite.aggregation.SqlAggregator;
@@ -114,8 +115,10 @@ public class CalcitePlannerModuleTest extends 
CalciteTestBase
     EasyMock.expect(druidSchema2.getSchema()).andStubReturn(schema2);
     EasyMock.expect(druidSchema1.getSchemaName()).andStubReturn(SCHEMA_1);
     EasyMock.expect(druidSchema2.getSchemaName()).andStubReturn(SCHEMA_2);
-    
EasyMock.expect(druidSchema1.getSchemaResourceType(EasyMock.anyString())).andStubReturn(ResourceType.DATASOURCE);
-    
EasyMock.expect(druidSchema2.getSchemaResourceType(EasyMock.anyString())).andStubReturn("test");
+    EasyMock.expect(druidSchema1.getSchemaResource(EasyMock.anyString()))
+            .andStubReturn(new Resource("resource", ResourceType.DATASOURCE));
+    EasyMock.expect(druidSchema2.getSchemaResource(EasyMock.anyString()))
+            .andStubReturn(new Resource("resource", "test"));
     EasyMock.replay(druidSchema1, druidSchema2);
     aggregators = ImmutableSet.of();
     operatorConversions = ImmutableSet.of();
diff --git 
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/NamedSystemSchemaTest.java
 
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/NamedSystemSchemaTest.java
index 9c80ea1dd08..7e7a11e8d6a 100644
--- 
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/NamedSystemSchemaTest.java
+++ 
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/NamedSystemSchemaTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.druid.sql.calcite.schema;
 
+import org.apache.druid.server.security.Resource;
 import org.apache.druid.server.security.ResourceType;
 import org.apache.druid.sql.calcite.planner.PlannerConfig;
 import org.apache.druid.sql.calcite.util.CalciteTestBase;
@@ -63,7 +64,7 @@ public class NamedSystemSchemaTest extends CalciteTestBase
   {
     
EasyMock.expect(plannerConfig.isAuthorizeSystemTablesDirectly()).andReturn(false).once();
     EasyMock.replay(plannerConfig);
-    Assertions.assertNull(target.getSchemaResourceType("servers"));
+    Assertions.assertNull(target.getSchemaResource("servers"));
     EasyMock.verify(plannerConfig);
   }
 
@@ -72,7 +73,7 @@ public class NamedSystemSchemaTest extends CalciteTestBase
   {
     
EasyMock.expect(plannerConfig.isAuthorizeSystemTablesDirectly()).andReturn(true).once();
     EasyMock.replay(plannerConfig);
-    Assertions.assertEquals(ResourceType.SYSTEM_TABLE, 
target.getSchemaResourceType("servers"));
+    Assertions.assertEquals(new Resource("servers", 
ResourceType.SYSTEM_TABLE), target.getSchemaResource("servers"));
     EasyMock.verify(plannerConfig);
   }
 }
diff --git 
a/sql/src/test/java/org/apache/druid/sql/calcite/schema/SchemaUtilsTest.java 
b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SchemaUtilsTest.java
new file mode 100644
index 00000000000..19af13e5bbc
--- /dev/null
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/schema/SchemaUtilsTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.sql.calcite.schema;
+
+import org.apache.druid.server.security.Access;
+import org.apache.druid.server.security.AuthenticationResult;
+import org.apache.druid.server.security.Authorizer;
+import org.apache.druid.server.security.AuthorizerMapper;
+import org.apache.druid.server.security.Resource;
+import org.apache.druid.server.security.ResourceType;
+import org.apache.druid.sql.calcite.util.CalciteTestBase;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.Set;
+
+public class SchemaUtilsTest extends CalciteTestBase
+{
+  private static final String ALLOWED = "allowed";
+  private static final AuthenticationResult AUTH_RESULT =
+      new AuthenticationResult("someone", "authorizer", null, null);
+
+  private static final AuthorizerMapper AUTHORIZER_MAPPER = new 
AuthorizerMapper(null)
+  {
+    @Override
+    public Authorizer getAuthorizer(String name)
+    {
+      return (authenticationResult, resource, action) ->
+          ALLOWED.equals(resource.getName()) ? Access.OK : Access.DENIED;
+    }
+  };
+
+  @Test
+  public void testFilterVisibleResourcesMapsManyNamesToOneResource()
+  {
+    final Resource resource = new Resource(ALLOWED, ResourceType.DATASOURCE);
+    Assertions.assertEquals(
+        Set.of("a", "b", "c"),
+        SchemaUtils.filterVisibleResources(
+            AUTHORIZER_MAPPER,
+            AUTH_RESULT,
+            List.of("a", "b", "c"),
+            _ -> resource
+        )
+    );
+  }
+
+  @Test
+  public void testFilterVisibleResourcesHidesNamesBehindADeniedResource()
+  {
+    final Resource resource = new Resource("denied", ResourceType.DATASOURCE);
+    Assertions.assertEquals(
+        Set.of(),
+        SchemaUtils.filterVisibleResources(
+            AUTHORIZER_MAPPER,
+            AUTH_RESULT,
+            List.of("a", "b"),
+            _ -> resource
+        )
+    );
+  }
+
+  @Test
+  public void testFilterVisibleResourcesAlwaysShowsNamesWithNoResource()
+  {
+    Assertions.assertEquals(
+        Set.of("a", "b"),
+        SchemaUtils.filterVisibleResources(AUTHORIZER_MAPPER, AUTH_RESULT, 
List.of("a", "b"), _ -> null)
+    );
+  }
+
+  @Test
+  public void testFilterVisibleTablesAuthorizesOnEachOwnName()
+  {
+    Assertions.assertEquals(
+        Set.of(ALLOWED),
+        SchemaUtils.filterVisibleTables(
+            AUTHORIZER_MAPPER,
+            AUTH_RESULT,
+            List.of(ALLOWED, "other"),
+            ResourceType.DATASOURCE
+        )
+    );
+  }
+
+  @Test
+  public void testIsTableVisible()
+  {
+    Assertions.assertTrue(
+        SchemaUtils.isTableVisible(AUTHORIZER_MAPPER, AUTH_RESULT, ALLOWED, 
ResourceType.DATASOURCE)
+    );
+    Assertions.assertFalse(
+        SchemaUtils.isTableVisible(AUTHORIZER_MAPPER, AUTH_RESULT, "other", 
ResourceType.DATASOURCE)
+    );
+  }
+}


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

Reply via email to