/* * eXist Open Source Native XML Database * Copyright (C) 2001-2017 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.exist.http; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.dom.persistent.BinaryDocument; import org.exist.dom.persistent.DocumentImpl; import org.exist.security.Subject; import org.exist.source.DBSource; import org.exist.source.Source; import org.exist.storage.BrokerPool; import org.exist.storage.DBBroker; import org.exist.storage.XQueryPool; import org.exist.storage.lock.Lock.LockMode; import org.exist.xmldb.XmldbURI; import org.exist.xquery.CompiledXQuery; import org.exist.xquery.XQuery; import org.exist.xquery.XQueryContext; import org.exist.xquery.value.AnyURIValue; import org.exist.xquery.value.Sequence; import javax.servlet.http.HttpSessionListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSession; import java.util.Optional; import java.util.Properties; /** * Executes an XQuery script whose filename is retrieved from the * java option 'org.exist.http.session_create_listener' when an * HTTP session is created and 'org.exist.http.session_destroy_listener' * when an HTTP session is destroyed. * <p> * If the java option is not set, then do nothing. * <p> * If the java option is set, then retrieve the script from the file * or resource designated by the value of the property. Execute the * XQuery script to record the creation or destruction of a HTTP session. */ public class AuditTrailSessionListener implements HttpSessionListener { private static final Logger LOG = LogManager.getLogger(AuditTrailSessionListener.class); public static final String REGISTER_CREATE_XQUERY_SCRIPT_PROPERTY = "org.exist.http.session_create_listener"; public static final String REGISTER_DESTROY_XQUERY_SCRIPT_PROPERTY = "org.exist.http.session_destroy_listener"; @Override public void sessionCreated(final HttpSessionEvent sessionEvent) { final HttpSession session = sessionEvent.getSession(); LOG.info("Session created " + session.getId()); final String xqueryResourcePath = System.getProperty(REGISTER_CREATE_XQUERY_SCRIPT_PROPERTY); executeXQuery(xqueryResourcePath); } @Override public void sessionDestroyed(final HttpSessionEvent sessionEvent) { final HttpSession session = (sessionEvent != null) ? sessionEvent.getSession() : null; if (session != null) { LOG.info("Destroyed session " + session.getId()); } else { LOG.info("Destroyed session"); } final String xqueryResourcePath = System.getProperty(REGISTER_DESTROY_XQUERY_SCRIPT_PROPERTY); executeXQuery(xqueryResourcePath); } private void executeXQuery(String xqueryResourcePath) { if (xqueryResourcePath != null && xqueryResourcePath.length() > 0) { xqueryResourcePath = xqueryResourcePath.trim(); try { final BrokerPool pool = BrokerPool.getInstance(); final Subject sysSubject = pool.getSecurityManager().getSystemSubject(); DocumentImpl resource = null; try (final DBBroker broker = pool.get(Optional.of(sysSubject))) { if (broker == null) { LOG.error("Unable to retrieve DBBroker for " + sysSubject.getName()); return; } final XmldbURI pathUri = XmldbURI.create(xqueryResourcePath); resource = broker.getXMLResource(pathUri, LockMode.READ_LOCK); final Source source; if (resource != null) { if (LOG.isTraceEnabled()) { LOG.trace("Resource [" + xqueryResourcePath + "] exists."); } source = new DBSource(broker, (BinaryDocument) resource, true); } else { LOG.error("Resource [" + xqueryResourcePath + "] does not exist."); return; } final XQuery xquery = pool.getXQueryService(); if (xquery == null) { LOG.error("broker unable to retrieve XQueryService"); return; } final XQueryPool xqpool = pool.getXQueryPool(); CompiledXQuery compiled = xqpool.borrowCompiledXQuery(broker, source); final XQueryContext context; if (compiled == null) { context = new XQueryContext(broker.getBrokerPool()); } else { context = compiled.getContext(); } context.setStaticallyKnownDocuments(new XmldbURI[]{pathUri}); context.setBaseURI(new AnyURIValue(pathUri.toString())); if (compiled == null) { compiled = xquery.compile(broker, context, source); } else { compiled.getContext().updateContext(context); context.getWatchDog().reset(); } final Properties outputProperties = new Properties(); try { final long startTime = System.currentTimeMillis(); final Sequence result = xquery.execute(broker, compiled, null, outputProperties); final long queryTime = System.currentTimeMillis() - startTime; if (LOG.isTraceEnabled()) { LOG.trace("XQuery execution results: " + result.toString() + " in " + queryTime + "ms."); } } finally { xqpool.returnCompiledXQuery(source, compiled); } } finally { if (resource != null) { resource.getUpdateLock().release(LockMode.READ_LOCK); } } } catch (final Exception e) { LOG.error("Exception while executing [" + xqueryResourcePath + "] script", e); } } } }