cgivre commented on code in PR #3056:
URL: https://github.com/apache/drill/pull/3056#discussion_r3699226600


##########
distribution/src/main/resources/ranger/ranger-drill-audit.xml:
##########
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+  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.
+-->
+<configuration>
+  <!-- Audit log destination. Set to Solr or HDFS for persistent audit storage.

Review Comment:
   By default, I think we should set the logging to the Drillbit log.  We 
should however include this in the documentation so that a user would know how 
to configure the Ranger logging.



##########
drill-ranger/drill-ranger-plugin/src/main/java/org/apache/ranger/authorization/drill/authorizer/DrillAccessControl.java:
##########
@@ -0,0 +1,287 @@
+/*
+ * 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.ranger.authorization.drill.authorizer;
+
+
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ranger.authorization.drill.resource.DrillAccessType;
+import org.apache.ranger.authorization.drill.resource.DrillResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Drill-facing authorization facade and single entry point for all Ranger
+ * access checks from Drill core hook points.
+ *
+ * <p>This class is designed to minimize the code changes required in Drill 
core.
+ * Each hook point is a single static method call:</p>
+ *
+ * <pre>{@code
+ * if (!DrillAccessControl.checkTableAccess(userName, storageEngineName, 
schemaPath, tableName)) {
+ *   throw UserException.permissionError()
+ *       .message("Access denied for user %s on table %s.%s", userName, 
schemaPath, tableName)
+ *       .build();
+ * }
+ * }</pre>
+ *
+ * <p>The class is initialized once at Drillbit startup via {@link 
#init(String)}.
+ * Until initialized, {@link #isEnabled()} returns {@code false} and all checks
+ * pass (fail-open), so the plugin is non-intrusive when disabled.</p>
+ *
+ * <p>The service name is read from the configuration property
+ * {@code ranger.plugin.drill.service.name} (defined in 
ranger-drill-security.xml),
+ * but can also be passed directly to {@link #init(String)} for 
flexibility.</p>
+ */
+public class DrillAccessControl {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(DrillAccessControl.class);

Review Comment:
   Nit:  It is a Drill convention to call the logger `logger`. 



##########
drill-ranger/drill-ranger-plugin/src/main/java/org/apache/ranger/authorization/drill/authorizer/ValidationLevel.java:
##########
@@ -0,0 +1,32 @@
+/*
+ * 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.ranger.authorization.drill.authorizer;
+
+/**
+ * Resource validation level enum.
+ * Controls the depth of validation in the validateResource method.
+ */
+public enum ValidationLevel {

Review Comment:
   Does this need to exist as a separate class or is there some other place for 
it that would make sense?



##########
drill-ranger/drill-ranger-plugin/src/main/java/org/apache/ranger/authorization/drill/authorizer/DrillAuthorizer.java:
##########
@@ -0,0 +1,186 @@
+/*
+ * 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.ranger.authorization.drill.authorizer;
+
+import org.apache.ranger.authorization.drill.resource.DrillAccessResource;
+import org.apache.ranger.authorization.drill.resource.DrillAccessType;
+import org.apache.ranger.authorization.drill.resource.DrillRangerAccessRequest;
+import org.apache.ranger.authorization.drill.resource.DrillResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.Set;
+
+public class DrillAuthorizer {
+  private static final Logger LOG = 
LoggerFactory.getLogger(DrillAuthorizer.class);

Review Comment:
   Nit:  Drill convention is to name the logger `logger`.  Here and elsewhere.



##########
drill-ranger/drill-ranger-plugin/src/main/java/org/apache/ranger/authorization/drill/authorizer/DrillAccessControl.java:
##########
@@ -0,0 +1,287 @@
+/*
+ * 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.ranger.authorization.drill.authorizer;
+
+
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.ranger.authorization.drill.resource.DrillAccessType;
+import org.apache.ranger.authorization.drill.resource.DrillResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Drill-facing authorization facade and single entry point for all Ranger
+ * access checks from Drill core hook points.
+ *
+ * <p>This class is designed to minimize the code changes required in Drill 
core.
+ * Each hook point is a single static method call:</p>
+ *
+ * <pre>{@code
+ * if (!DrillAccessControl.checkTableAccess(userName, storageEngineName, 
schemaPath, tableName)) {
+ *   throw UserException.permissionError()
+ *       .message("Access denied for user %s on table %s.%s", userName, 
schemaPath, tableName)
+ *       .build();
+ * }
+ * }</pre>
+ *
+ * <p>The class is initialized once at Drillbit startup via {@link 
#init(String)}.
+ * Until initialized, {@link #isEnabled()} returns {@code false} and all checks
+ * pass (fail-open), so the plugin is non-intrusive when disabled.</p>
+ *
+ * <p>The service name is read from the configuration property
+ * {@code ranger.plugin.drill.service.name} (defined in 
ranger-drill-security.xml),
+ * but can also be passed directly to {@link #init(String)} for 
flexibility.</p>
+ */
+public class DrillAccessControl {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(DrillAccessControl.class);
+
+  private static volatile boolean enabled = false;
+  private static volatile DrillAuthorizer authorizer;
+
+  // Set of system schemas that bypass authorization (information_schema, sys, 
etc.)
+  // Stored in uppercase; isSystemSchema() uppercases input before lookup so 
the
+  // bypass is case-insensitive (e.g. "information_schema", 
"INFORMATION_SCHEMA",
+  // "Sys", "SYS" all match).
+  private static final Set<String> SYSTEM_SCHEMAS = new 
HashSet<>(Arrays.asList(
+      "INFORMATION_SCHEMA", "SYS"
+  ));
+
+  private DrillAccessControl() {
+  }
+
+  /**
+   * Initializes the Ranger Drill plugin. Called once at Drillbit startup.
+   *
+   * @param serviceName the Ranger service instance name (must match a service 
created in Ranger Admin)
+   */
+  public static synchronized void init(String serviceName) {
+    if (authorizer != null) {
+      return;
+    }
+    try {
+      LOG.info("Initializing Ranger Drill authorization plugin for service: 
{}", serviceName);
+      authorizer = new DrillAuthorizer(serviceName);
+      enabled = true;
+      LOG.info("Ranger Drill authorization plugin initialized successfully");
+    } catch (Exception e) {
+      LOG.error("Failed to initialize Ranger Drill plugin — authorization 
DISABLED", e);
+      throw new RuntimeException("Failed to initialize Ranger Drill plugin — 
authorization disabled "+ serviceName + " with exception: " + e);
+    }
+  }
+
+  /**
+   * @return {@code true} if the Ranger plugin is initialized
+   */
+  public static boolean isEnabled() {
+    return enabled;
+  }
+
+  /**
+   * Resolves the OS-level groups for a given user via Hadoop UGI.
+   *
+   * @param user the username
+   * @return a set of group names (never null, empty on failure)
+   */
+  public static Set<String> getUserGroups(String user) {
+    if (user == null || user.trim().isEmpty()) {
+      return Collections.emptySet();
+    }
+    try {
+      UserGroupInformation ugi = UserGroupInformation.createRemoteUser(user);
+      String[] groups = ugi.getGroupNames();
+      return groups == null ? Collections.emptySet() : new 
HashSet<>(Arrays.asList(groups));
+    } catch (Exception e) {
+      LOG.warn("Failed to determine groups for user={}", user, e);
+      return Collections.emptySet();
+    }
+  }
+
+  /**
+   * Checks table-level access. This is the external entry point that accepts
+   * the operator as a string (e.g. "SELECT", "CREATE"). The string is
+   * converted to {@link DrillAccessType}; if the conversion fails the
+   * operator is not a supported access type and access is denied.
+   *
+   * @param user       the username requesting access
+   * @param dataSource the Drill storage plugin name (e.g. "dfs", "hbase")
+   * @param schema     the schema path (e.g. "dfs.tmp")
+   * @param table      the table name
+   * @param operator   the access type string (e.g. "SELECT", "CREATE")
+   * @return {@code true} if access is allowed
+   */
+  public static boolean checkTableAccess(String user, String dataSource, 
String schema,
+      String table, String operator) {
+    DrillAccessType accessType;
+    try {
+      accessType = DrillAccessType.valueOf(operator.toUpperCase());
+    } catch (Exception e) {
+      LOG.error("Unsupported access type '{}', denied table access for 
user={}, schema={}, table={}",

Review Comment:
   What does the user see if they are trying to do something that is not 
allowed?



##########
drill-ranger/drill-ranger-plugin/src/main/java/org/apache/ranger/authorization/drill/resource/DrillAccessType.java:
##########
@@ -0,0 +1,21 @@
+/*
+ * 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.ranger.authorization.drill.resource;
+
+public enum DrillAccessType {

Review Comment:
   How are CTEs handled?



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