All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.orientechnologies.security.auditing.ODefaultAuditing Maven / Gradle / Ivy

/**
 * Copyright 2010-2016 OrientDB LTD (http://orientdb.com)
 * 

* Licensed 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. *

* For more information: http://www.orientdb.com */ package com.orientechnologies.security.auditing; import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.Orient; import com.orientechnologies.orient.core.db.ODatabaseDocumentInternal; import com.orientechnologies.orient.core.db.ODatabaseInternal; import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener; import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal; import com.orientechnologies.orient.core.metadata.schema.OClass; import com.orientechnologies.orient.core.metadata.schema.OSchema; import com.orientechnologies.orient.core.metadata.schema.OType; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.security.OAuditingOperation; import com.orientechnologies.orient.server.OServer; import com.orientechnologies.orient.server.OSystemDatabase; import com.orientechnologies.orient.server.config.OServerConfigurationManager; import com.orientechnologies.orient.server.distributed.ODistributedLifecycleListener; import com.orientechnologies.orient.server.distributed.ODistributedServerManager; import com.orientechnologies.orient.server.security.OAuditingService; import java.io.*; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Created by Enrico Risa on 10/04/15. */ public class ODefaultAuditing implements OAuditingService, ODatabaseLifecycleListener, ODistributedLifecycleListener { public static final String AUDITING_LOG_CLASSNAME = "OAuditingLog"; private boolean enabled = true; private OServer server; private OAuditingHook globalHook; private Map hooks; protected static final String DEFAULT_FILE_AUDITING_DB_CONFIG = "default-auditing-config.json"; protected static final String FILE_AUDITING_DB_CONFIG = "auditing-config.json"; private OAuditingDistribConfig distribConfig; private OSystemDBImporter systemDbImporter; public static final String IMPORTER_FLAG = "AUDITING_IMPORTER"; private class OAuditingDistribConfig extends OAuditingConfig { private boolean onNodeJoinedEnabled = false; private String onNodeJoinedMessage = "The node ${node} has joined"; private boolean onNodeLeftEnabled = false; private String onNodeLeftMessage = "The node ${node} has left"; public OAuditingDistribConfig(final ODocument cfg) { if (cfg.containsField("onNodeJoinedEnabled")) onNodeJoinedEnabled = cfg.field("onNodeJoinedEnabled"); onNodeJoinedMessage = cfg.field("onNodeJoinedMessage"); if (cfg.containsField("onNodeLeftEnabled")) onNodeLeftEnabled = cfg.field("onNodeLeftEnabled"); onNodeLeftMessage = cfg.field("onNodeLeftMessage"); } @Override public String formatMessage(final OAuditingOperation op, final String subject) { if (op == OAuditingOperation.NODEJOINED) { return resolveMessage(onNodeJoinedMessage, "node", subject); } else if (op == OAuditingOperation.NODELEFT) { return resolveMessage(onNodeLeftMessage, "node", subject); } return subject; } @Override public boolean isEnabled(OAuditingOperation op) { if (op == OAuditingOperation.NODEJOINED) { return onNodeJoinedEnabled; } else if (op == OAuditingOperation.NODELEFT) { return onNodeLeftEnabled; } return false; } } public ODefaultAuditing() { hooks = new ConcurrentHashMap(20); } @Override public PRIORITY getPriority() { return PRIORITY.LAST; } @Override public void onCreate(final ODatabaseInternal iDatabase) { // Don't audit system database events. if (iDatabase.getName().equalsIgnoreCase(OSystemDatabase.SYSTEM_DB_NAME)) return; final OAuditingHook hook = defaultHook(iDatabase); hooks.put(iDatabase.getName(), hook); iDatabase.registerHook(hook); iDatabase.registerListener(hook); } private OAuditingHook defaultHook(final ODatabaseInternal iDatabase) { final File auditingFileConfig = getConfigFile(iDatabase.getName()); String content = null; if (auditingFileConfig != null && auditingFileConfig.exists()) { content = getContent(auditingFileConfig); } else { final InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(DEFAULT_FILE_AUDITING_DB_CONFIG); try { if (resourceAsStream == null) OLogManager.instance().error(this, "defaultHook() resourceAsStream is null", null); content = getString(resourceAsStream); if (auditingFileConfig != null) { try { auditingFileConfig.getParentFile().mkdirs(); auditingFileConfig.createNewFile(); final FileOutputStream f = new FileOutputStream(auditingFileConfig); try { f.write(content.getBytes()); f.flush(); } finally { f.close(); } } catch (IOException e) { content = "{}"; OLogManager.instance().error(this, "Cannot save auditing file configuration", e); } } } finally { try { if (resourceAsStream != null) resourceAsStream.close(); } catch (IOException e) { OLogManager.instance().error(this, "Cannot read auditing file configuration", e); } } } final ODocument cfg = new ODocument().fromJSON(content, "noMap"); return new OAuditingHook(cfg, server); } private String getContent(File auditingFileConfig) { FileInputStream f = null; String content = ""; try { f = new FileInputStream(auditingFileConfig); final byte[] buffer = new byte[(int) auditingFileConfig.length()]; f.read(buffer); content = new String(buffer); } catch (Exception e) { content = "{}"; OLogManager.instance().error(this, "Cannot get auditing file configuration", e); } finally { if (f != null) { try { f.close(); } catch (IOException e) { OLogManager.instance().error(this, "Cannot get auditing file configuration", e); } } } return content; } public String getString(InputStream is) { try { int ch; final StringBuilder sb = new StringBuilder(); while ((ch = is.read()) != -1) sb.append((char) ch); return sb.toString(); } catch (IOException e) { OLogManager.instance().error(this, "Cannot get default auditing file configuration", e); return "{}"; } } @Override public void onOpen(ODatabaseInternal iDatabase) { // Don't audit system database events. if (iDatabase.getName().equalsIgnoreCase(OSystemDatabase.SYSTEM_DB_NAME)) return; // If the database has been opened by the auditing importer, do not hook it. if (iDatabase.getProperty(IMPORTER_FLAG) != null) return; OAuditingHook oAuditingHook = hooks.get(iDatabase.getName()); if (oAuditingHook == null) { oAuditingHook = defaultHook(iDatabase); hooks.put(iDatabase.getName(), oAuditingHook); } iDatabase.registerHook(oAuditingHook); iDatabase.registerListener(oAuditingHook); } @Override public void onClose(ODatabaseInternal iDatabase) { final OAuditingHook oAuditingHook = hooks.get(iDatabase.getName()); if (oAuditingHook != null) { iDatabase.unregisterHook(oAuditingHook); iDatabase.unregisterListener(oAuditingHook); } } @Override public void onDrop(ODatabaseInternal iDatabase) { onClose(iDatabase); final OAuditingHook oAuditingHook = hooks.get(iDatabase.getName()); if (oAuditingHook != null) { oAuditingHook.shutdown(false); } File f = getConfigFile(iDatabase.getName()); if (f != null && f.exists()) { OLogManager.instance().info(this, "Removing Auditing config for db : %s", iDatabase.getName()); f.delete(); } } private File getConfigFile(String iDatabaseName) { return new File(server.getDatabaseDirectory() + iDatabaseName + File.separator + FILE_AUDITING_DB_CONFIG); } @Override public void onCreateClass(ODatabaseInternal iDatabase, OClass iClass) { final OAuditingHook oAuditingHook = hooks.get(iDatabase.getName()); if (oAuditingHook != null) { oAuditingHook.onCreateClass(iClass); } } @Override public void onDropClass(ODatabaseInternal iDatabase, OClass iClass) { final OAuditingHook oAuditingHook = hooks.get(iDatabase.getName()); if (oAuditingHook != null) { oAuditingHook.onDropClass(iClass); } } @Override public void onLocalNodeConfigurationRequest(ODocument iConfiguration) { } protected void updateConfigOnDisk(final String iDatabaseName, final ODocument cfg) throws IOException { final File auditingFileConfig = getConfigFile(iDatabaseName); if (auditingFileConfig != null) { final FileOutputStream f = new FileOutputStream(auditingFileConfig); try { f.write(cfg.toJSON("prettyPrint=true").getBytes()); f.flush(); } finally { f.close(); } } } ////// // ODistributedLifecycleListener public boolean onNodeJoining(String iNode) { return true; } public void onNodeJoined(String iNode) { if (distribConfig != null && distribConfig.isEnabled(OAuditingOperation.NODEJOINED)) log(OAuditingOperation.NODEJOINED, distribConfig.formatMessage(OAuditingOperation.NODEJOINED, iNode)); } public void onNodeLeft(String iNode) { if (distribConfig != null && distribConfig.isEnabled(OAuditingOperation.NODELEFT)) log(OAuditingOperation.NODELEFT, distribConfig.formatMessage(OAuditingOperation.NODELEFT, iNode)); } public void onDatabaseChangeStatus(String iNode, String iDatabaseName, ODistributedServerManager.DB_STATUS iNewStatus) { } @Deprecated public static String getClusterName(final String dbName) { return dbName + "_auditing"; } public static String getClassName(final String dbName) { return dbName + AUDITING_LOG_CLASSNAME; } ////// // OAuditingService public void changeConfig(final String iDatabaseName, final ODocument cfg) throws IOException { // This should never happen, but just in case... // Don't audit system database events. if (iDatabaseName != null && iDatabaseName.equalsIgnoreCase(OSystemDatabase.SYSTEM_DB_NAME)) return; hooks.put(iDatabaseName, new OAuditingHook(cfg, server)); updateConfigOnDisk(iDatabaseName, cfg); } public ODocument getConfig(final String iDatabaseName) { return hooks.get(iDatabaseName).getConfiguration(); } /** * Primarily used for global logging events (e.g., NODEJOINED, NODELEFT). */ public void log(final OAuditingOperation operation, final String message) { log(operation, null, null, message); } /** * Primarily used for global logging events (e.g., NODEJOINED, NODELEFT). */ public void log(final OAuditingOperation operation, final String username, final String message) { log(operation, null, username, message); } /** * Primarily used for global logging events (e.g., NODEJOINED, NODELEFT). */ public void log(final OAuditingOperation operation, final String dbName, final String username, final String message) { // If dbName is null, then we submit the log message to the global auditing hook. // Otherwise, we submit it to the hook associated with dbName. if (dbName != null) { final OAuditingHook oAuditingHook = hooks.get(dbName); if (oAuditingHook != null) { oAuditingHook.log(operation, dbName, username, message); } else { // Use the global hook. globalHook.log(operation, dbName, username, message); } } else { // Use the global hook. if (globalHook == null) OLogManager.instance() .error(this, "Default Auditing is disabled, cannot log: op=%s db='%s' user=%s message='%s'", null, operation, dbName, username, message); else globalHook.log(operation, dbName, username, message); } } private void createClassIfNotExists() { final ODatabaseDocumentInternal currentDB = ODatabaseRecordThreadLocal.instance().getIfDefined(); ODatabaseDocumentInternal sysdb = null; try { sysdb = server.getSystemDatabase().openSystemDatabase(); OSchema schema = sysdb.getMetadata().getSchema(); OClass cls = schema.getClass(AUDITING_LOG_CLASSNAME); if (cls == null) { cls = sysdb.getMetadata().getSchema().createClass(AUDITING_LOG_CLASSNAME); cls.createProperty("date", OType.DATETIME); cls.createProperty("user", OType.STRING); cls.createProperty("operation", OType.BYTE); cls.createProperty("record", OType.LINK); cls.createProperty("changes", OType.EMBEDDED); cls.createProperty("note", OType.STRING); cls.createProperty("database", OType.STRING); } } catch (Exception e) { OLogManager.instance().error(this, "Creating auditing class exception", e); } finally { if (sysdb != null) sysdb.close(); if (currentDB != null) ODatabaseRecordThreadLocal.instance().set(currentDB); else ODatabaseRecordThreadLocal.instance().remove(); } } ////// // OAuditingService (OSecurityComponent) // Called once the Server is running. public void active() { createClassIfNotExists(); globalHook = new OAuditingHook(server); Orient.instance().addDbLifecycleListener(this); if (server.getDistributedManager() != null) { server.getDistributedManager().registerLifecycleListener(this); } if (systemDbImporter != null && systemDbImporter.isEnabled()) { systemDbImporter.start(); } } public void config(final OServer oServer, final OServerConfigurationManager serverCfg, final ODocument jsonConfig) { server = oServer; try { if (jsonConfig.containsField("enabled")) { enabled = jsonConfig.field("enabled"); } if (jsonConfig.containsField("distributed")) { ODocument distribDoc = jsonConfig.field("distributed"); distribConfig = new OAuditingDistribConfig(distribDoc); } if (jsonConfig.containsField("systemImport")) { ODocument sysImport = jsonConfig.field("systemImport"); systemDbImporter = new OSystemDBImporter(server, sysImport); } } catch (Exception ex) { OLogManager.instance().error(this, "config()", ex); } } // Called on removal of the component. public void dispose() { if (systemDbImporter != null && systemDbImporter.isEnabled()) { systemDbImporter.shutdown(); } if (server.getDistributedManager() != null) { server.getDistributedManager().unregisterLifecycleListener(this); } Orient.instance().removeDbLifecycleListener(this); if (globalHook != null) { globalHook.shutdown(false); globalHook = null; } } // OSecurityComponent public boolean isEnabled() { return enabled; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy