[Improvement](auth)(step-1) add ranger authorizer for hms catalog (#17153)
This commit is contained in:
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user