blob: c6a9c66f5fdc0ad3298d1f2409a4944156b5402c [file] [log] [blame]
/*
* 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.hive.authorizer;
import java.util.*;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.RangerAccessResource;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
import com.google.common.collect.Lists;
public class RangerHiveAuditHandler extends RangerDefaultAuditHandler {
private static final Log LOG = LogFactory.getLog(RangerDefaultAuditHandler.class);
public static final String ACCESS_TYPE_ROWFILTER = "ROW_FILTER";
Collection<AuthzAuditEvent> auditEvents = null;
boolean deniedExists = false;
public RangerHiveAuditHandler() {
super();
}
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);
auditEvent.setAccessType(accessType);
auditEvent.setResourcePath(resourcePath);
auditEvent.setResourceType("@" + resourceType); // to be consistent with earlier release
if (request instanceof RangerHiveAccessRequest && resource instanceof RangerHiveResource) {
RangerHiveAccessRequest hiveAccessRequest = (RangerHiveAccessRequest) request;
RangerHiveResource hiveResource = (RangerHiveResource) resource;
HiveAccessType hiveAccessType = hiveAccessRequest.getHiveAccessType();
if (hiveAccessType == HiveAccessType.USE && hiveResource.getObjectType() == HiveObjectType.DATABASE && StringUtils.isBlank(hiveResource.getDatabase())) {
// this should happen only for SHOWDATABASES
auditEvent.setTags(null);
}
if (hiveAccessType == HiveAccessType.REPLADMIN ) {
// In case of REPL commands Audit should show what REPL Command instead of REPLADMIN access type
String context = request.getRequestData();
String replAccessType = getReplCmd(context);
auditEvent.setAccessType(replAccessType);
}
if (hiveAccessType == HiveAccessType.SERVICEADMIN) {
String hiveOperationType = request.getAction();
String commandStr = request.getRequestData();
if (HiveOperationType.KILL_QUERY.name().equalsIgnoreCase(hiveOperationType)) {
String queryId = getServiceAdminQueryId(commandStr);
if (!StringUtils.isEmpty(queryId)) {
auditEvent.setRequestData(queryId);
}
commandStr = getServiceAdminCmd(commandStr);
if (StringUtils.isEmpty(commandStr)) {
commandStr = hiveAccessType.name();
}
}
auditEvent.setAccessType(commandStr);
}
}
return auditEvent;
}
AuthzAuditEvent createAuditEvent(RangerAccessResult result) {
AuthzAuditEvent ret = null;
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 RangerHiveAccessRequest) {
RangerHiveAccessRequest hiveRequest = (RangerHiveAccessRequest) request;
accessType = hiveRequest.getHiveAccessType().toString();
}
if (StringUtils.isEmpty(accessType)) {
accessType = request.getAccessType();
}
ret = createAuditEvent(result, accessType, resourcePath);
}
return ret;
}
List<AuthzAuditEvent> createAuditEvents(Collection<RangerAccessResult> results) {
Map<Long, AuthzAuditEvent> auditEvents = new HashMap<Long, AuthzAuditEvent>();
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();
if (auditEvents.containsKey(policyId)) { // add this result to existing event by updating column values
AuthzAuditEvent auditEvent = auditEvents.get(policyId);
RangerHiveAccessRequest request = (RangerHiveAccessRequest)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) {
auditEvents.put(policyId, auditEvent);
}
}
}
}
}
List<AuthzAuditEvent> result;
if (deniedAuditEvent == null) {
result = new ArrayList<>(auditEvents.values());
} else {
result = Lists.newArrayList(deniedAuditEvent);
}
return result;
}
@Override
public void processResult(RangerAccessResult result) {
if(! result.getIsAudited()) {
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, RangerHiveAuthorizer should call isAccessAllowed(Collection<requests>) only for this condition
*/
@Override
public void processResults(Collection<RangerAccessResult> results) {
List<AuthzAuditEvent> auditEvents = createAuditEvents(results);
for(AuthzAuditEvent auditEvent : auditEvents) {
addAuthzAuditEvent(auditEvent);
}
}
public void logAuditEventForDfs(String userName, String dfsCommand, boolean accessGranted, int repositoryType, String repositoryName) {
AuthzAuditEvent auditEvent = new AuthzAuditEvent();
auditEvent.setAclEnforcer(moduleName);
auditEvent.setResourceType("@dfs"); // to be consistent with earlier release
auditEvent.setAccessType("DFS");
auditEvent.setAction("DFS");
auditEvent.setUser(userName);
auditEvent.setAccessResult((short)(accessGranted ? 1 : 0));
auditEvent.setEventTime(new Date());
auditEvent.setRepositoryType(repositoryType);
auditEvent.setRepositoryName(repositoryName);
auditEvent.setRequestData(dfsCommand);
auditEvent.setResourcePath(dfsCommand);
if(LOG.isDebugEnabled()){
LOG.debug("Logging DFS event " + auditEvent.toString());
}
addAuthzAuditEvent(auditEvent);
}
public void flushAudit() {
if(auditEvents == null) {
return;
}
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) {
if(auditEvents == null) {
auditEvents = new ArrayList<AuthzAuditEvent>();
}
auditEvents.add(auditEvent);
if(auditEvent.getAccessResult() == 0) {
deniedExists = true;
}
}
}
private String getReplCmd(String cmdString) {
String ret = "REPL";
if (cmdString != null) {
String[] cmd = cmdString.trim().split("\\s+");
if (!ArrayUtils.isEmpty(cmd) && cmd.length > 2) {
ret = cmd[0] + " " + cmd[1];
}
}
return ret;
}
private String getServiceAdminCmd(String cmdString) {
String ret = "SERVICE ADMIN";
if (cmdString != null) {
String[] cmd = cmdString.trim().split("\\s+");
if (!ArrayUtils.isEmpty(cmd) && cmd.length > 1) {
ret = cmd[0] + " " + cmd[1];
}
}
return ret;
}
private String getServiceAdminQueryId(String cmdString) {
String ret = "QUERY ID = ";
if (cmdString != null) {
String[] cmd = cmdString.trim().split("\\s+");
if (!ArrayUtils.isEmpty(cmd) && cmd.length > 2) {
ret = ret + cmd[2];
}
}
return ret;
}
}