/* * 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.destination; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; import org.apache.ranger.audit.dao.DaoManager; import org.apache.ranger.audit.entity.AuthzAuditEventDbObj; import org.apache.ranger.audit.model.AuditEventBase; import org.apache.ranger.audit.provider.MiscUtil; public class DBAuditDestination extends AuditDestination { private static final Log logger = LogFactory .getLog(DBAuditDestination.class); public static final String PROP_DB_JDBC_DRIVER = "jdbc.driver"; public static final String PROP_DB_JDBC_URL = "jdbc.url"; public static final String PROP_DB_USER = "user"; public static final String PROP_DB_PASSWORD = "password"; public static final String PROP_DB_PASSWORD_ALIAS = "password.alias"; private EntityManagerFactory entityManagerFactory; private DaoManager daoManager; private String jdbcDriver = null; private String jdbcURL = null; private String dbUser = null; private String dbPasswordAlias = "auditDBCred"; public DBAuditDestination() { logger.info("DBAuditDestination() called"); } @Override public void init(Properties props, String propPrefix) { logger.info("init() called"); super.init(props, propPrefix); // Initial connect connect(); // initialize the database related classes AuthzAuditEventDbObj.init(props); } /* * (non-Javadoc) * * @see * org.apache.ranger.audit.provider.AuditHandler#logger(java.util.Collection * ) */ @Override public boolean log(Collection<AuditEventBase> events) { boolean retValue = false; logStatusIfRequired(); addTotalCount(events.size()); if (beginTransaction()) { boolean isFailed = false; for (AuditEventBase event : events) { try { event.persist(daoManager); } catch (Throwable t) { logger.error("Error persisting data. event=" + event, t); isFailed = true; break; } } if (isFailed) { retValue = false; rollbackTransaction(); } else { retValue = commitTransaction(); } } if (retValue) { addSuccessCount(events.size()); } else { addDeferredCount(events.size()); } return retValue; } @Override public void stop() { cleanUp(); super.stop(); } // Local methods protected void connect() { if (isDbConnected()) { return; } try { jdbcDriver = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_DB_JDBC_DRIVER); jdbcURL = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_DB_JDBC_URL); dbUser = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_DB_USER); String dbPasswordFromProp = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_DB_PASSWORD); String tmpAlias = MiscUtil.getStringProperty(props, propPrefix + "." + PROP_DB_PASSWORD_ALIAS); dbPasswordAlias = tmpAlias != null ? tmpAlias : dbPasswordAlias; String credFile = MiscUtil.getStringProperty(props, AUDIT_DB_CREDENTIAL_PROVIDER_FILE); if (jdbcDriver == null || jdbcDriver.isEmpty()) { logger.fatal("JDBC driver not provided. Set property name " + propPrefix + "." + PROP_DB_JDBC_DRIVER); return; } if (jdbcURL == null || jdbcURL.isEmpty()) { logger.fatal("JDBC URL not provided. Set property name " + propPrefix + "." + PROP_DB_JDBC_URL); return; } if (dbUser == null || dbUser.isEmpty()) { logger.fatal("DB user not provided. Set property name " + propPrefix + "." + PROP_DB_USER); return; } String dbPassword = MiscUtil.getCredentialString(credFile, dbPasswordAlias); if (dbPassword == null || dbPassword.isEmpty()) { // If password is not in credential store, let's try password // from property dbPassword = dbPasswordFromProp; } if (dbPassword == null || dbPassword.isEmpty()) { logger.warn("DB password not provided. Will assume it is empty and continue"); } logger.info("JDBC Driver=" + jdbcDriver + ", JDBC URL=" + jdbcURL + ", dbUser=" + dbUser + ", passwordAlias=" + dbPasswordAlias + ", credFile=" + credFile + ", usingPassword=" + (dbPassword == null ? "no" : "yes")); Map<String, String> dbProperties = new HashMap<String, String>(); dbProperties.put("javax.persistence.jdbc.driver", jdbcDriver); dbProperties.put("javax.persistence.jdbc.url", jdbcURL); dbProperties.put("javax.persistence.jdbc.user", dbUser); if (dbPassword != null) { dbProperties.put("javax.persistence.jdbc.password", dbPassword); } entityManagerFactory = Persistence.createEntityManagerFactory( "xa_server", dbProperties); logger.info("entityManagerFactory=" + entityManagerFactory); daoManager = new DaoManager(); daoManager.setEntityManagerFactory(entityManagerFactory); // this forces the connection to be made to DB if (daoManager.getEntityManager() == null) { logger.error("Error connecting audit database. EntityManager is null. dbURL=" + jdbcURL + ", dbUser=" + dbUser); } else { logger.info("Connected to audit database. dbURL=" + jdbcURL + ", dbUser=" + dbUser); } } catch (Throwable t) { logger.error("Error connecting audit database. dbURL=" + jdbcURL + ", dbUser=" + dbUser, t); } } private synchronized void cleanUp() { logger.info("DBAuditDestination: cleanUp()"); try { if (entityManagerFactory != null && entityManagerFactory.isOpen()) { entityManagerFactory.close(); } } catch (Exception excp) { logger.error("DBAuditDestination.cleanUp(): failed", excp); } finally { entityManagerFactory = null; daoManager = null; } logStatus(); } private EntityManager getEntityManager() { DaoManager daoMgr = daoManager; if (daoMgr != null) { try { return daoMgr.getEntityManager(); } catch (Exception excp) { logger.error("DBAuditDestination.getEntityManager(): failed", excp); cleanUp(); } } return null; } private boolean isDbConnected() { EntityManager em = getEntityManager(); return em != null && em.isOpen(); } private void clearEntityManager() { try { EntityManager em = getEntityManager(); if (em != null) { em.clear(); } } catch (Exception excp) { logger.warn("DBAuditDestination.clearEntityManager(): failed", excp); } } private EntityTransaction getTransaction() { if (!isDbConnected()) { connect(); } EntityManager em = getEntityManager(); return em != null ? em.getTransaction() : null; } private boolean beginTransaction() { EntityTransaction trx = getTransaction(); if (trx != null && !trx.isActive()) { trx.begin(); } if (trx == null) { logger.warn("DBAuditDestination.beginTransaction(): trx is null"); } return trx != null; } private boolean commitTransaction() { boolean ret = false; EntityTransaction trx = null; try { trx = getTransaction(); if (trx != null && trx.isActive()) { trx.commit(); ret = true; } else { throw new Exception("trx is null or not active"); } } catch (Throwable excp) { logger.error("DBAuditDestination.commitTransaction(): failed", excp); cleanUp(); // so that next insert will try to init() } finally { clearEntityManager(); } return ret; } private boolean rollbackTransaction() { boolean ret = false; EntityTransaction trx = null; try { trx = getTransaction(); if (trx != null && trx.isActive()) { trx.rollback(); ret = true; } else { throw new Exception("trx is null or not active"); } } catch (Throwable excp) { logger.error("DBAuditDestination.rollbackTransaction(): failed", excp); cleanUp(); // so that next insert will try to init() } finally { clearEntityManager(); } return ret; } }