/* * 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.plugin.audit; import java.io.Serializable; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ranger.audit.model.AuthzAuditEvent; import org.apache.ranger.audit.provider.AuditProviderFactory; import org.apache.ranger.audit.provider.MiscUtil; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; import org.apache.ranger.plugin.contextenricher.RangerTagForEval; import org.apache.ranger.plugin.policyengine.*; import org.apache.ranger.plugin.util.RangerAccessRequestUtil; import org.codehaus.jackson.map.ObjectMapper; public class RangerDefaultAuditHandler implements RangerAccessResultProcessor { protected static final String RangerModuleName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_RANGER_MODULE_ACL_NAME_PROP , RangerHadoopConstants.DEFAULT_RANGER_MODULE_ACL_NAME); private static final Log LOG = LogFactory.getLog(RangerDefaultAuditHandler.class); static long sequenceNumber; private static String UUID = MiscUtil.generateUniqueId(); private static AtomicInteger counter = new AtomicInteger(0); public RangerDefaultAuditHandler() { } @Override public void processResult(RangerAccessResult result) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.processResult(" + result + ")"); } AuthzAuditEvent event = getAuthzEvents(result); logAuthzAudit(event); if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.processResult(" + result + ")"); } } @Override public void processResults(Collection<RangerAccessResult> results) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.processResults(" + results + ")"); } Collection<AuthzAuditEvent> events = getAuthzEvents(results); if (events != null) { logAuthzAudits(events); } if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.processResults(" + results + ")"); } } public AuthzAuditEvent getAuthzEvents(RangerAccessResult result) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.getAuthzEvents(" + result + ")"); } AuthzAuditEvent ret = null; RangerAccessRequest request = result != null ? result.getAccessRequest() : null; if(request != null && result != null && result.getIsAudited()) { //RangerServiceDef serviceDef = result.getServiceDef(); RangerAccessResource resource = request.getResource(); String resourceType = resource == null ? null : resource.getLeafName(); String resourcePath = resource == null ? null : resource.getAsString(); ret = createAuthzAuditEvent(); ret.setRepositoryName(result.getServiceName()); ret.setRepositoryType(result.getServiceType()); ret.setResourceType(resourceType); ret.setResourcePath(resourcePath); ret.setRequestData(request.getRequestData()); ret.setEventTime(request.getAccessTime()); ret.setUser(request.getUser()); ret.setAction(request.getAccessType()); ret.setAccessResult((short) (result.getIsAllowed() ? 1 : 0)); ret.setPolicyId(result.getPolicyId()); ret.setAccessType(request.getAction()); ret.setClientIP(request.getClientIPAddress()); ret.setClientType(request.getClientType()); ret.setSessionId(request.getSessionId()); ret.setAclEnforcer(RangerModuleName); Set<String> tags = getTags(request); if (tags != null) { ret.setTags(tags); } ret.setAdditionalInfo(getAdditionalInfo(request)); ret.setClusterName(request.getClusterName()); populateDefaults(ret); } if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.getAuthzEvents(" + result + "): " + ret); } return ret; } public Collection<AuthzAuditEvent> getAuthzEvents(Collection<RangerAccessResult> results) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.getAuthzEvents(" + results + ")"); } List<AuthzAuditEvent> ret = null; if(results != null) { // TODO: optimize the number of audit logs created for(RangerAccessResult result : results) { AuthzAuditEvent event = getAuthzEvents(result); if(event == null) { continue; } if(ret == null) { ret = new ArrayList<>(); } ret.add(event); } } if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.getAuthzEvents(" + results + "): " + ret); } return ret; } public void logAuthzAudit(AuthzAuditEvent auditEvent) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.logAuthzAudit(" + auditEvent + ")"); } if(auditEvent != null) { populateDefaults(auditEvent); if(!AuditProviderFactory.getAuditProvider().log(auditEvent)) { MiscUtil.logErrorMessageByInterval(LOG, "fail to log audit event " + auditEvent); } } if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.logAuthzAudit(" + auditEvent + ")"); } } private void populateDefaults(AuthzAuditEvent auditEvent) { if( auditEvent.getAclEnforcer() == null || auditEvent.getAclEnforcer().isEmpty()) { auditEvent.setAclEnforcer("ranger-acl"); // TODO: review } if (auditEvent.getAgentHostname() == null || auditEvent.getAgentHostname().isEmpty()) { auditEvent.setAgentHostname(MiscUtil.getHostname()); } if (auditEvent.getLogType() == null || auditEvent.getLogType().isEmpty()) { auditEvent.setLogType("RangerAudit"); } if (auditEvent.getEventId() == null || auditEvent.getEventId().isEmpty()) { auditEvent.setEventId(generateNextAuditEventId()); } auditEvent.setSeqNum(sequenceNumber++); } public void logAuthzAudits(Collection<AuthzAuditEvent> auditEvents) { if(LOG.isDebugEnabled()) { LOG.debug("==> RangerDefaultAuditHandler.logAuthzAudits(" + auditEvents + ")"); } if(auditEvents != null) { for(AuthzAuditEvent auditEvent : auditEvents) { logAuthzAudit(auditEvent); } } if(LOG.isDebugEnabled()) { LOG.debug("<== RangerDefaultAuditHandler.logAuthzAudits(" + auditEvents + ")"); } } public AuthzAuditEvent createAuthzAuditEvent() { return new AuthzAuditEvent(); } protected final Set<String> getTags(RangerAccessRequest request) { Set<String> ret = null; Set<RangerTagForEval> tags = RangerAccessRequestUtil.getRequestTagsFromContext(request.getContext()); if (CollectionUtils.isNotEmpty(tags)) { ret = new HashSet<>(); for (RangerTagForEval tag : tags) { ret.add(writeObjectAsString(tag)); } } return ret; } public String getAdditionalInfo(RangerAccessRequest request) { if (StringUtils.isBlank(request.getRemoteIPAddress()) && CollectionUtils.isEmpty(request.getForwardedAddresses())) { return null; } StringBuilder sb = new StringBuilder(); sb.append("{\"remote-ip-address\":").append(request.getRemoteIPAddress()) .append(", \"forwarded-ip-addresses\":[").append(StringUtils.join(request.getForwardedAddresses(), ", ")).append("]"); return sb.toString(); } private String generateNextAuditEventId() { int nextId = counter.getAndIncrement(); if(nextId == Integer.MAX_VALUE) { // reset UUID and counter UUID = MiscUtil.generateUniqueId(); counter = new AtomicInteger(0); } return UUID + "-" + Integer.toString(nextId); } private String writeObjectAsString(Serializable obj) { ObjectMapper mapper = new ObjectMapper(); String jsonStr = StringUtils.EMPTY; try { jsonStr = mapper.writeValueAsString(obj); } catch (Exception e) { LOG.error("Cannot create JSON string for object:[" + obj + "]", e); } return jsonStr; } }