org.apache.ranger.audit.provider.solr.SolrAuditProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ranger.audit.provider.solr.SolrAuditProvider.java

Source

/*
 * 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.audit.provider.solr;

import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.Date;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ranger.audit.destination.AuditDestination;
import org.apache.ranger.audit.model.AuditEventBase;
import org.apache.ranger.audit.model.AuthzAuditEvent;
import org.apache.ranger.audit.provider.MiscUtil;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;

public class SolrAuditProvider extends AuditDestination {
    private static final Log LOG = LogFactory.getLog(SolrAuditProvider.class);

    public static final String AUDIT_MAX_QUEUE_SIZE_PROP = "xasecure.audit.solr.async.max.queue.size";
    public static final String AUDIT_MAX_FLUSH_INTERVAL_PROP = "xasecure.audit.solr.async.max.flush.interval.ms";
    public static final String AUDIT_RETRY_WAIT_PROP = "xasecure.audit.solr.retry.ms";

    static final Object lock = new Object();
    volatile SolrClient solrClient = null;
    Date lastConnectTime = null;
    long lastFailTime = 0;

    int retryWaitTime = 30000;

    public SolrAuditProvider() {
    }

    @Override
    public void init(Properties props) {
        LOG.info("init() called");
        super.init(props);

        retryWaitTime = MiscUtil.getIntProperty(props, AUDIT_RETRY_WAIT_PROP, retryWaitTime);
    }

    void connect() {
        SolrClient me = solrClient;
        if (me == null) {
            synchronized (lock) {
                me = solrClient;
                if (me == null) {
                    final String solrURL = MiscUtil.getStringProperty(props, "xasecure.audit.solr.solr_url");

                    if (lastConnectTime != null) {
                        // Let's wait for enough time before retrying
                        long diff = System.currentTimeMillis() - lastConnectTime.getTime();
                        if (diff < retryWaitTime) {
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Ignore connecting to solr url=" + solrURL + ", lastConnect=" + diff
                                        + "ms");
                            }
                            return;
                        }
                    }
                    lastConnectTime = new Date();

                    if (solrURL == null || solrURL.isEmpty()) {
                        LOG.fatal("Solr URL for Audit is empty");
                        return;
                    }

                    try {
                        // TODO: Need to support SolrCloud also
                        PrivilegedExceptionAction<SolrClient> action = new PrivilegedExceptionAction<SolrClient>() {
                            @Override
                            public SolrClient run() throws Exception {
                                SolrClient solrClient = new HttpSolrClient(solrURL);
                                return solrClient;
                            };
                        };
                        UserGroupInformation ugi = MiscUtil.getUGILoginUser();
                        if (ugi != null) {
                            solrClient = ugi.doAs(action);
                        } else {
                            solrClient = action.run();
                        }
                        me = solrClient;
                        if (solrClient instanceof HttpSolrClient) {
                            HttpSolrClient httpSolrClient = (HttpSolrClient) solrClient;
                            httpSolrClient.setAllowCompression(true);
                            httpSolrClient.setConnectionTimeout(1000);
                            // solrClient.setSoTimeout(10000);
                            httpSolrClient.setMaxRetries(1);
                        }
                    } catch (Throwable t) {
                        LOG.fatal("Can't connect to Solr server. URL=" + solrURL, t);
                    }
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.apache.ranger.audit.provider.AuditProvider#log(org.apache.ranger.
     * audit.model.AuditEventBase)
     */
    @Override
    public boolean log(AuditEventBase event) {
        if (!(event instanceof AuthzAuditEvent)) {
            LOG.error(event.getClass().getName() + " audit event class type is not supported");
            return false;
        }
        AuthzAuditEvent authzEvent = (AuthzAuditEvent) event;
        // TODO: This should be done at a higher level

        if (authzEvent.getAgentHostname() == null) {
            authzEvent.setAgentHostname(MiscUtil.getHostname());
        }

        if (authzEvent.getLogType() == null) {
            authzEvent.setLogType("RangerAudit");
        }

        if (authzEvent.getEventId() == null) {
            authzEvent.setEventId(MiscUtil.generateUniqueId());
        }

        try {
            if (solrClient == null) {
                connect();
                if (solrClient == null) {
                    // Solr is still not initialized. So need to throw error
                    return false;
                }
            }

            if (lastFailTime > 0) {
                long diff = System.currentTimeMillis() - lastFailTime;
                if (diff < retryWaitTime) {
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Ignore sending audit. lastConnect=" + diff + " ms");
                    }
                    return false;
                }
            }
            // Convert AuditEventBase to Solr document
            final SolrInputDocument document = toSolrDoc(authzEvent);
            UpdateResponse response = null;
            PrivilegedExceptionAction<UpdateResponse> action = new PrivilegedExceptionAction<UpdateResponse>() {
                @Override
                public UpdateResponse run() throws Exception {
                    UpdateResponse response = solrClient.add(document);
                    return response;
                };
            };
            UserGroupInformation ugi = MiscUtil.getUGILoginUser();
            if (ugi != null) {
                response = ugi.doAs(action);
            } else {
                response = action.run();
            }
            if (response.getStatus() != 0) {
                lastFailTime = System.currentTimeMillis();

                // System.out.println("Response=" + response.toString()
                // + ", status= " + response.getStatus() + ", event="
                // + event);
                // throw new Exception("Aborting. event=" + event +
                // ", response="
                // + response.toString());
            } else {
                lastFailTime = 0;
            }

        } catch (Throwable t) {
            LOG.error("Error sending message to Solr", t);
            return false;
        }
        return true;
    }

    @Override
    public boolean log(Collection<AuditEventBase> events) {
        for (AuditEventBase event : events) {
            log(event);
        }
        return true;
    }

    @Override
    public boolean logJSON(String event) {
        AuditEventBase eventObj = MiscUtil.fromJson(event, AuthzAuditEvent.class);
        return log(eventObj);
    }

    @Override
    public boolean logJSON(Collection<String> events) {
        for (String event : events) {
            logJSON(event);
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.ranger.audit.provider.AuditProvider#start()
     */
    @Override
    public void start() {
        connect();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.ranger.audit.provider.AuditProvider#stop()
     */
    @Override
    public void stop() {
        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.ranger.audit.provider.AuditProvider#waitToComplete()
     */
    @Override
    public void waitToComplete() {

    }

    @Override
    public void waitToComplete(long timeout) {

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.ranger.audit.provider.AuditProvider#flush()
     */
    @Override
    public void flush() {
        // TODO Auto-generated method stub

    }

    SolrInputDocument toSolrDoc(AuthzAuditEvent auditEvent) {
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", auditEvent.getEventId());
        doc.addField("access", auditEvent.getAccessType());
        doc.addField("enforcer", auditEvent.getAclEnforcer());
        doc.addField("agent", auditEvent.getAgentId());
        doc.addField("repo", auditEvent.getRepositoryName());
        doc.addField("sess", auditEvent.getSessionId());
        doc.addField("reqUser", auditEvent.getUser());
        doc.addField("reqData", auditEvent.getRequestData());
        doc.addField("resource", auditEvent.getResourcePath());
        doc.addField("cliIP", auditEvent.getClientIP());
        doc.addField("logType", auditEvent.getLogType());
        doc.addField("result", auditEvent.getAccessResult());
        doc.addField("policy", auditEvent.getPolicyId());
        doc.addField("repoType", auditEvent.getRepositoryType());
        doc.addField("resType", auditEvent.getResourceType());
        doc.addField("reason", auditEvent.getResultReason());
        doc.addField("action", auditEvent.getAction());
        doc.addField("evtTime", auditEvent.getEventTime());
        doc.addField("tags", auditEvent.getTags());
        return doc;
    }

    public boolean isAsync() {
        return true;
    }

}