This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 449f2953c9 [Improvement](auth)(step-1) add ranger authorizer for hms
catalog (#17153)
449f2953c9 is described below
commit 449f2953c9c017f5a9a3152ff6faa563d881e617
Author: Yulei-Yang <[email protected]>
AuthorDate: Fri Mar 3 09:45:08 2023 +0800
[Improvement](auth)(step-1) add ranger authorizer for hms catalog (#17153)
---
fe/fe-core/pom.xml | 17 ++
.../doris/catalog/authorizer/HiveAccessType.java | 23 ++
.../doris/catalog/authorizer/HiveObjectType.java | 22 ++
.../authorizer/RangerHiveAccessController.java | 190 +++++++++++++++
.../RangerHiveAccessControllerFactory.java | 30 +++
.../catalog/authorizer/RangerHiveAuditHandler.java | 270 +++++++++++++++++++++
.../authorizer/RangerHiveAuthorizerProvider.java | 49 ++++
.../doris/catalog/authorizer/RangerHivePlugin.java | 27 +++
.../catalog/authorizer/RangerHiveResource.java | 96 ++++++++
9 files changed, 724 insertions(+)
diff --git a/fe/fe-core/pom.xml b/fe/fe-core/pom.xml
index 086ed1e92a..15c847f00d 100644
--- a/fe/fe-core/pom.xml
+++ b/fe/fe-core/pom.xml
@@ -820,6 +820,23 @@ under the License.
</exclusions>
</dependency>
+ <!--
https://mvnrepository.com/artifact/org.apache.ranger/ranger-plugins-common -->
+ <dependency>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger-plugins-common</artifactId>
+ <version>2.3.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ </exclusion>
+ <exclusion>
+
<artifactId>elasticsearch-rest-high-level-client</artifactId>
+ <groupId>org.elasticsearch.client</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
</dependencies>
<build>
<finalName>doris-fe</finalName>
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveAccessType.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveAccessType.java
new file mode 100644
index 0000000000..233f3c463a
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveAccessType.java
@@ -0,0 +1,23 @@
+// 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.doris.catalog.authorizer;
+
+public enum HiveAccessType {
+ NONE, CREATE, ALTER, DROP, INDEX, LOCK, SELECT, UPDATE, USE, READ, WRITE,
ALL, SERVICEADMIN,
+ TEMPUDFADMIN;
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveObjectType.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveObjectType.java
new file mode 100644
index 0000000000..94f4f7e684
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/HiveObjectType.java
@@ -0,0 +1,22 @@
+// 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.doris.catalog.authorizer;
+
+public enum HiveObjectType {
+ NONE, DATABASE, TABLE, VIEW, INDEX, COLUMN, FUNCTION;
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
new file mode 100644
index 0000000000..2c819334de
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
@@ -0,0 +1,190 @@
+// 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.doris.catalog.authorizer;
+
+import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.common.AuthorizationException;
+import org.apache.doris.mysql.privilege.CatalogAccessController;
+import org.apache.doris.mysql.privilege.PrivPredicate;
+
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RangerHiveAccessController implements CatalogAccessController {
+ public static final String CLIENT_TYPE_DORIS = "doris";
+ private static final Logger LOG =
LogManager.getLogger(RangerHiveAccessController.class);
+ private RangerHivePlugin hivePlugin;
+ private RangerHiveAuditHandler auditHandler;
+
+ public RangerHiveAccessController(Map<String, String> properties) {
+ String serviceName = properties.get("ranger.service.name");
+ hivePlugin = new RangerHivePlugin(serviceName);
+ auditHandler = new RangerHiveAuditHandler(hivePlugin.getConfig());
+ }
+
+ private RangerAccessRequestImpl createRequest(UserIdentity currentUser,
HiveAccessType accessType) {
+ RangerAccessRequestImpl request = new RangerAccessRequestImpl();
+ request.setUser(currentUser.getQualifiedUser());
+ request.setUserRoles(currentUser.getRoles());
+ request.setAction(accessType.name());
+ if (accessType == HiveAccessType.USE) {
+ request.setAccessType(RangerPolicyEngine.ANY_ACCESS);
+ } else {
+ request.setAccessType(accessType.name().toLowerCase());
+ }
+ request.setClientIPAddress(currentUser.getHost());
+ request.setClientType(CLIENT_TYPE_DORIS);
+ request.setAccessTime(new Date());
+
+ return request;
+ }
+
+ private void checkPrivileges(UserIdentity currentUser, HiveAccessType
accessType,
+ List<RangerHiveResource> hiveResources) throws
AuthorizationException {
+ try {
+ List<RangerAccessRequest> requests = new ArrayList<>();
+ for (RangerHiveResource resource : hiveResources) {
+ RangerAccessRequestImpl request = createRequest(currentUser,
accessType);
+ request.setResource(resource);
+
+ requests.add(request);
+ }
+
+ Collection<RangerAccessResult> results =
hivePlugin.isAccessAllowed(requests, auditHandler);
+ for (RangerAccessResult result : results) {
+ LOG.debug("match policy:" + result.getPolicyId());
+ if (!result.getIsAllowed()) {
+ LOG.debug(result.getReason());
+ throw new AuthorizationException(String.format(
+ "Permission denied: user [%s] does not have privilege
for [%s] command on [%s]",
+ currentUser.getQualifiedUser(), accessType.name(),
+
result.getAccessRequest().getResource().getAsString()));
+ }
+ }
+ } finally {
+ auditHandler.flushAudit();
+ }
+ }
+
+ private boolean checkPrivilege(UserIdentity currentUser, HiveAccessType
accessType,
+ RangerHiveResource resource) {
+ RangerAccessRequestImpl request = createRequest(currentUser,
accessType);
+ request.setResource(resource);
+
+ RangerAccessResult result = hivePlugin.isAccessAllowed(request,
auditHandler);
+ auditHandler.flushAudit();
+
+ if (result == null) {
+ LOG.warn(String.format("Error getting authorizer result, please
check your ranger config. Request: %s",
+ request));
+ return false;
+ }
+
+ if (result.getIsAllowed()) {
+ return true;
+ } else {
+ LOG.debug(String.format(
+ "Permission denied: user [%s] does not have privilege for
[%s] command on [%s]",
+ currentUser.getQualifiedUser(), accessType.name(),
+ result.getAccessRequest().getResource().getAsString()));
+ return false;
+ }
+ }
+
+ public String getFilterExpr(UserIdentity currentUser, HiveAccessType
accessType,
+ RangerHiveResource resource) throws
HiveAccessControlException {
+ RangerAccessRequestImpl request = createRequest(currentUser,
accessType);
+ request.setResource(resource);
+ RangerAccessResult result = hivePlugin.isAccessAllowed(request,
auditHandler);
+ auditHandler.flushAudit();
+
+ return result.getFilterExpr();
+ }
+
+ public void getColumnMask(UserIdentity currentUser, HiveAccessType
accessType,
+ RangerHiveResource resource) {
+ RangerAccessRequestImpl request = createRequest(currentUser,
accessType);
+ request.setResource(resource);
+ RangerAccessResult result = hivePlugin.isAccessAllowed(request,
auditHandler);
+ auditHandler.flushAudit();
+
+ LOG.debug(String.format("maskType: %s, maskTypeDef: %s, maskedValue:
%s", result.getMaskType(),
+ result.getMaskTypeDef(), result.getMaskedValue()));
+ }
+
+ public HiveAccessType convertToAccessType(PrivPredicate predicate) {
+ if (predicate == PrivPredicate.SHOW) {
+ return HiveAccessType.USE;
+ } else if (predicate == PrivPredicate.ADMIN) {
+ return HiveAccessType.ALL;
+ } else if (predicate == PrivPredicate.LOAD) {
+ return HiveAccessType.UPDATE;
+ } else if (predicate == PrivPredicate.ALTER) {
+ return HiveAccessType.ALTER;
+ } else if (predicate == PrivPredicate.CREATE) {
+ return HiveAccessType.CREATE;
+ } else if (predicate == PrivPredicate.DROP) {
+ return HiveAccessType.DROP;
+ } else if (predicate == PrivPredicate.SELECT) {
+ return HiveAccessType.SELECT;
+ } else {
+ return HiveAccessType.NONE;
+ }
+ }
+
+ @Override
+ public boolean checkCtlPriv(UserIdentity currentUser, String ctl,
PrivPredicate wanted) {
+ return false;
+ }
+
+ @Override
+ public boolean checkDbPriv(UserIdentity currentUser, String ctl, String
db, PrivPredicate wanted) {
+ RangerHiveResource resource = new
RangerHiveResource(HiveObjectType.DATABASE, db);
+ return checkPrivilege(currentUser, convertToAccessType(wanted),
resource);
+ }
+
+ @Override
+ public boolean checkTblPriv(UserIdentity currentUser, String ctl, String
db, String tbl, PrivPredicate wanted) {
+ RangerHiveResource resource = new
RangerHiveResource(HiveObjectType.TABLE, db, tbl);
+ return checkPrivilege(currentUser, convertToAccessType(wanted),
resource);
+ }
+
+ @Override
+ public void checkColsPriv(UserIdentity currentUser, String ctl, String db,
String tbl, Set<String> cols,
+ PrivPredicate wanted) throws
AuthorizationException {
+ List<RangerHiveResource> resources = new ArrayList<>();
+ for (String col : cols) {
+ RangerHiveResource resource = new
RangerHiveResource(HiveObjectType.COLUMN, db, tbl, col);
+ resources.add(resource);
+ }
+
+ checkPrivileges(currentUser, convertToAccessType(wanted), resources);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessControllerFactory.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessControllerFactory.java
new file mode 100644
index 0000000000..3dc5e1c243
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessControllerFactory.java
@@ -0,0 +1,30 @@
+// 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.doris.catalog.authorizer;
+
+import org.apache.doris.mysql.privilege.AccessControllerFactory;
+import org.apache.doris.mysql.privilege.CatalogAccessController;
+
+import java.util.Map;
+
+public class RangerHiveAccessControllerFactory implements
AccessControllerFactory {
+ @Override
+ public CatalogAccessController createAccessController(Map<String, String>
prop) {
+ return new RangerHiveAccessController(prop);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuditHandler.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuditHandler.java
new file mode 100644
index 0000000000..6f68c378b4
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuditHandler.java
@@ -0,0 +1,270 @@
+// 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.doris.catalog.authorizer;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.hadoop.conf.Configuration;
+import
org.apache.hadoop.hive.ql.security.authorization.plugin.HiveOperationType;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
+import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
+import org.apache.ranger.plugin.model.RangerPolicy;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequest;
+import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
+import org.apache.ranger.plugin.policyengine.RangerAccessResource;
+import org.apache.ranger.plugin.policyengine.RangerAccessResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class RangerHiveAuditHandler extends RangerDefaultAuditHandler {
+
+ public static final String ACCESS_TYPE_ROWFILTER = "ROW_FILTER";
+ public static final String ACCESS_TYPE_INSERT = "INSERT";
+ public static final String ACCESS_TYPE_UPDATE = "UPDATE";
+ public static final String ACCESS_TYPE_DELETE = "DELETE";
+ public static final String ACCESS_TYPE_TRUNCATE = "TRUNCATE";
+ public static final String ACTION_TYPE_METADATA_OPERATION = "METADATA
OPERATION";
+ public static final String CONF_AUDIT_QUERY_REQUEST_SIZE =
"xasecure.audit.solr.limit.query.req.size";
+ public static final int DEFAULT_CONF_AUDIT_QUERY_REQUEST_SIZE =
Integer.MAX_VALUE;
+ private static final Logger LOG =
LoggerFactory.getLogger(RangerDefaultAuditHandler.class);
+ private static final Set<String> ROLE_OPS = new HashSet<>();
+
+ static {
+ for (HiveOperationType e : EnumSet.of(HiveOperationType.CREATEROLE,
HiveOperationType.DROPROLE,
+ HiveOperationType.SHOW_ROLES,
HiveOperationType.SHOW_ROLE_GRANT, HiveOperationType.SHOW_ROLE_PRINCIPALS,
+ HiveOperationType.GRANT_ROLE, HiveOperationType.REVOKE_ROLE)) {
+ ROLE_OPS.add(e.name());
+ }
+ }
+
+ private final int requestQuerySize;
+ private final Collection<AuthzAuditEvent> auditEvents = new ArrayList<>();
+ private boolean deniedExists = false;
+
+ public RangerHiveAuditHandler() {
+ super();
+ requestQuerySize = DEFAULT_CONF_AUDIT_QUERY_REQUEST_SIZE;
+ }
+
+ public RangerHiveAuditHandler(Configuration config) {
+ super(config);
+
+ int configRequestQuerySize =
config.getInt(CONF_AUDIT_QUERY_REQUEST_SIZE,
+ DEFAULT_CONF_AUDIT_QUERY_REQUEST_SIZE);
+
+ requestQuerySize = (configRequestQuerySize < 1) ?
DEFAULT_CONF_AUDIT_QUERY_REQUEST_SIZE :
+ configRequestQuerySize;
+ }
+
+ AuthzAuditEvent createAuditEvent(RangerAccessResult result, String
accessType, String resourcePath) {
+ RangerAccessRequest request = result.getAccessRequest();
+ RangerAccessResource resource = request.getResource();
+ String resourceType = resource != null ? resource.getLeafName() : null;
+
+ AuthzAuditEvent auditEvent = super.getAuthzEvents(result);
+
+ String resourcePathComputed = resourcePath;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("requestQuerySize = " + requestQuerySize);
+ }
+ if (StringUtils.isNotBlank(request.getRequestData()) &&
request.getRequestData().length() > requestQuerySize) {
+ auditEvent.setRequestData(request.getRequestData().substring(0,
requestQuerySize));
+ } else {
+ auditEvent.setRequestData(request.getRequestData());
+ }
+ auditEvent.setAccessType(accessType);
+ auditEvent.setResourcePath(resourcePathComputed);
+ auditEvent.setResourceType("@" + resourceType); // to be consistent
with earlier release
+
+ if (request instanceof RangerAccessRequestImpl && resource instanceof
RangerHiveResource) {
+ RangerAccessRequestImpl hiveAccessRequest =
(RangerAccessRequestImpl) request;
+ RangerHiveResource hiveResource = (RangerHiveResource) resource;
+ String hiveAccessType = hiveAccessRequest.getAccessType();
+
+ if (HiveAccessType.USE.toString().equalsIgnoreCase(hiveAccessType)
&& hiveResource.getObjectType()
+ == HiveObjectType.DATABASE &&
StringUtils.isBlank(hiveResource.getDatabase())) {
+ // this should happen only for SHOWDATABASES
+ auditEvent.setTags(null);
+ }
+ }
+
+ return auditEvent;
+ }
+
+ AuthzAuditEvent createAuditEvent(RangerAccessResult result) {
+ final AuthzAuditEvent ret;
+
+ RangerAccessRequest request = result.getAccessRequest();
+ RangerAccessResource resource = request.getResource();
+ String resourcePath = resource != null ? resource.getAsString() : null;
+ int policyType = result.getPolicyType();
+
+ if (policyType == RangerPolicy.POLICY_TYPE_DATAMASK &&
result.isMaskEnabled()) {
+ ret = createAuditEvent(result, result.getMaskType(), resourcePath);
+ } else if (policyType == RangerPolicy.POLICY_TYPE_ROWFILTER) {
+ ret = createAuditEvent(result, ACCESS_TYPE_ROWFILTER,
resourcePath);
+ } else if (policyType == RangerPolicy.POLICY_TYPE_ACCESS) {
+ String accessType = null;
+
+ if (request instanceof RangerAccessRequestImpl) {
+ RangerAccessRequestImpl hiveRequest =
(RangerAccessRequestImpl) request;
+
+ accessType = hiveRequest.getAccessType();
+
+ String action = request.getAction();
+ if (ACTION_TYPE_METADATA_OPERATION.equals(action)) {
+ accessType = ACTION_TYPE_METADATA_OPERATION;
+ } else if
(HiveAccessType.UPDATE.toString().equalsIgnoreCase(accessType)) {
+ String commandStr = request.getRequestData();
+ if (StringUtils.isNotBlank(commandStr)) {
+ if (StringUtils.startsWithIgnoreCase(commandStr,
ACCESS_TYPE_INSERT)) {
+ accessType = ACCESS_TYPE_INSERT;
+ } else if
(StringUtils.startsWithIgnoreCase(commandStr, ACCESS_TYPE_UPDATE)) {
+ accessType = ACCESS_TYPE_UPDATE;
+ } else if
(StringUtils.startsWithIgnoreCase(commandStr, ACCESS_TYPE_DELETE)) {
+ accessType = ACCESS_TYPE_DELETE;
+ } else if
(StringUtils.startsWithIgnoreCase(commandStr, ACCESS_TYPE_TRUNCATE)) {
+ accessType = ACCESS_TYPE_TRUNCATE;
+ }
+ }
+ }
+ }
+
+ if (StringUtils.isEmpty(accessType)) {
+ accessType = request.getAccessType();
+ }
+
+ ret = createAuditEvent(result, accessType, resourcePath);
+ } else {
+ ret = null;
+ }
+
+ return ret;
+ }
+
+ List<AuthzAuditEvent> createAuditEvents(Collection<RangerAccessResult>
results) {
+
+ Map<Long, AuthzAuditEvent> auditEventsMap = new HashMap<>();
+ Iterator<RangerAccessResult> iterator = results.iterator();
+ AuthzAuditEvent deniedAuditEvent = null;
+ while (iterator.hasNext() && deniedAuditEvent == null) {
+ RangerAccessResult result = iterator.next();
+ if (result.getIsAudited()) {
+ if (!result.getIsAllowed()) {
+ deniedAuditEvent = createAuditEvent(result);
+ } else {
+ long policyId = result.getPolicyId();
+ // add this result to existing event by updating column
values
+ if (auditEventsMap.containsKey(policyId)) {
+ AuthzAuditEvent auditEvent =
auditEventsMap.get(policyId);
+ RangerAccessRequestImpl request =
(RangerAccessRequestImpl) result.getAccessRequest();
+ RangerHiveResource resource = (RangerHiveResource)
request.getResource();
+ String resourcePath = auditEvent.getResourcePath() +
"," + resource.getColumn();
+ auditEvent.setResourcePath(resourcePath);
+ Set<String> tags = getTags(request);
+ if (tags != null) {
+ auditEvent.getTags().addAll(tags);
+ }
+ } else { // new event as this approval was due to a
different policy.
+ AuthzAuditEvent auditEvent = createAuditEvent(result);
+
+ if (auditEvent != null) {
+ auditEventsMap.put(policyId, auditEvent);
+ }
+ }
+ }
+ }
+ }
+ final List<AuthzAuditEvent> result = (deniedAuditEvent == null) ? new
ArrayList<>(auditEventsMap.values())
+ : Collections.singletonList(deniedAuditEvent);
+
+ return result;
+ }
+
+ @Override
+ public void processResult(RangerAccessResult result) {
+ if (result == null || !result.getIsAudited()) {
+ return;
+ }
+
+ if (skipFilterOperationAuditing(result)) {
+ return;
+ }
+
+ AuthzAuditEvent auditEvent = createAuditEvent(result);
+
+ if (auditEvent != null) {
+ addAuthzAuditEvent(auditEvent);
+ }
+ }
+
+ /**
+ * This method is expected to be called ONLY to process the results for
multiple-columns in a table.
+ * To ensure this, RangerHiveAccessController should call
isAccessAllowed(Collection<requests>) only for this
+ * condition
+ */
+ @Override
+ public void processResults(Collection<RangerAccessResult> results) {
+ List<AuthzAuditEvent> result = createAuditEvents(results);
+ for (AuthzAuditEvent auditEvent : result) {
+ addAuthzAuditEvent(auditEvent);
+ }
+ }
+
+ public void flushAudit() {
+ for (AuthzAuditEvent auditEvent : auditEvents) {
+ if (deniedExists && auditEvent.getAccessResult() != 0) { // if
deny exists, skip logging for allowed results
+ continue;
+ }
+
+ super.logAuthzAudit(auditEvent);
+ }
+ }
+
+ private void addAuthzAuditEvent(AuthzAuditEvent auditEvent) {
+ if (auditEvent != null) {
+ auditEvents.add(auditEvent);
+
+ if (auditEvent.getAccessResult() == 0) {
+ deniedExists = true;
+ }
+ }
+ }
+
+ private boolean skipFilterOperationAuditing(RangerAccessResult result) {
+ boolean ret = false;
+ RangerAccessRequest accessRequest = result.getAccessRequest();
+ if (accessRequest != null) {
+ String action = accessRequest.getAction();
+ if (ACTION_TYPE_METADATA_OPERATION.equals(action) &&
!result.getIsAllowed()) {
+ ret = true;
+ }
+ }
+ return ret;
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuthorizerProvider.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuthorizerProvider.java
new file mode 100644
index 0000000000..5415496e16
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAuthorizerProvider.java
@@ -0,0 +1,49 @@
+// 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.doris.catalog.authorizer;
+
+import java.util.Map;
+
+public class RangerHiveAuthorizerProvider {
+
+ private static volatile Map<String, RangerHivePlugin> hivePluginMap = null;
+
+ /**
+ * if some catalogs use a same ranger hive service, make them share the
same authorizer plugin
+ *
+ * @param serviceUrl url of ranger admin
+ * @param serviceName name of hive service in ranger admin
+ * @return
+ */
+ public static RangerHivePlugin getHivePlugin(String serviceUrl, String
serviceName) {
+ String id = serviceUrl + serviceName;
+
+ if (!hivePluginMap.containsKey(id)) {
+ synchronized (RangerHiveAuthorizerProvider.class) {
+ if (!hivePluginMap.containsKey(id)) {
+ RangerHivePlugin plugin = new RangerHivePlugin(serviceUrl
+ serviceName);
+ plugin.init();
+
+ hivePluginMap.put(id, plugin);
+ }
+ }
+ }
+
+ return hivePluginMap.get(id);
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHivePlugin.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHivePlugin.java
new file mode 100644
index 0000000000..b562eee5a9
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHivePlugin.java
@@ -0,0 +1,27 @@
+// 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.doris.catalog.authorizer;
+
+import org.apache.ranger.plugin.service.RangerBasePlugin;
+
+public class RangerHivePlugin extends RangerBasePlugin {
+ public RangerHivePlugin(String serviceName) {
+ super(serviceName, null, null);
+ super.init();
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveResource.java
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveResource.java
new file mode 100644
index 0000000000..51f28b91ff
--- /dev/null
+++
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveResource.java
@@ -0,0 +1,96 @@
+// 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.doris.catalog.authorizer;
+
+import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
+
+public class RangerHiveResource extends RangerAccessResourceImpl {
+ public static final String KEY_DATABASE = "database";
+ public static final String KEY_TABLE = "table";
+ public static final String KEY_UDF = "udf";
+ public static final String KEY_COLUMN = "column";
+ private HiveObjectType objectType;
+
+ //FirstLevelResource => Database
+ //SecondLevelResource => Table or UDF
+ //ThirdLevelResource => column
+ public RangerHiveResource(HiveObjectType objectType, String
firstLevelResource) {
+ this(objectType, firstLevelResource, null, null);
+ }
+
+ public RangerHiveResource(HiveObjectType objectType, String
firstLevelResource, String secondLevelResource) {
+ this(objectType, firstLevelResource, secondLevelResource, null);
+ }
+
+ public RangerHiveResource(HiveObjectType objectType, String
firstLevelResource, String secondLevelResource,
+ String thirdLevelResource) {
+ this.objectType = objectType;
+
+ // set essential info according to objectType
+ switch (objectType) {
+ case DATABASE:
+ setValue(KEY_DATABASE, firstLevelResource);
+ break;
+
+ case FUNCTION:
+ if (firstLevelResource == null) {
+ firstLevelResource = "";
+ }
+ setValue(KEY_DATABASE, firstLevelResource);
+ setValue(KEY_UDF, secondLevelResource);
+ break;
+
+ case COLUMN:
+ setValue(KEY_DATABASE, firstLevelResource);
+ setValue(KEY_TABLE, secondLevelResource);
+ setValue(KEY_COLUMN, thirdLevelResource);
+ break;
+
+ case TABLE:
+ case VIEW:
+ case INDEX:
+ setValue(KEY_DATABASE, firstLevelResource);
+ setValue(KEY_TABLE, secondLevelResource);
+ break;
+
+ case NONE:
+ default:
+ break;
+ }
+ }
+
+ public HiveObjectType getObjectType() {
+ return objectType;
+ }
+
+ public String getDatabase() {
+ return (String) getValue(KEY_DATABASE);
+ }
+
+ public String getTable() {
+ return (String) getValue(KEY_TABLE);
+ }
+
+ public String getUdf() {
+ return (String) getValue(KEY_UDF);
+ }
+
+ public String getColumn() {
+ return (String) getValue(KEY_COLUMN);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]