com.floragunn.searchguard.auditlog.sink.SinkProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dlic-search-guard-enterprise-modules Show documentation
Show all versions of dlic-search-guard-enterprise-modules Show documentation
Enterprise Modules for Search Guard
/*
* Copyright 2016-2018 by floragunn GmbH - All rights reserved
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed here is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* For use in a production environment you have to obtain a license
* from https://floragunn.com
*
*/
package com.floragunn.searchguard.auditlog.sink;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.threadpool.ThreadPool;
import com.floragunn.searchguard.dlic.rest.support.Utils;
import com.floragunn.searchguard.support.ConfigConstants;
public class SinkProvider {
protected final Logger log = LogManager.getLogger(this.getClass());
private static final String FALLBACKSINK_NAME = "fallback";
private static final String DEFAULTSINK_NAME = "default";
private final Client clientProvider;
private final ThreadPool threadPool;
private final Path configPath;
private final Settings settings;
final Map allSinks = new HashMap<>();
AuditLogSink defaultSink;
AuditLogSink fallbackSink;
public SinkProvider(final Settings settings, final Client clientProvider, ThreadPool threadPool, final Path configPath) {
this.settings = settings;
this.clientProvider = clientProvider;
this.threadPool = threadPool;
this.configPath = configPath;
// fall back sink, make sure we don't lose messages
String fallbackConfigPrefix = ConfigConstants.SEARCHGUARD_AUDIT_CONFIG_ENDPOINTS + "." + FALLBACKSINK_NAME;
Settings fallbackSinkSettings = settings.getAsSettings(fallbackConfigPrefix);
if(!fallbackSinkSettings.isEmpty()) {
this.fallbackSink = createSink(FALLBACKSINK_NAME, fallbackSinkSettings.get("type"), settings, fallbackConfigPrefix+".config");
}
// make sure we always have a fallback to write to
if (this.fallbackSink == null) {
this.fallbackSink = new DebugSink(FALLBACKSINK_NAME, settings, null);
}
allSinks.put(FALLBACKSINK_NAME, this.fallbackSink);
// create default sink
defaultSink = this.createSink(DEFAULTSINK_NAME, settings.get(ConfigConstants.SEARCHGUARD_AUDIT_TYPE_DEFAULT), settings, ConfigConstants.SEARCHGUARD_AUDIT_CONFIG_DEFAULT);
if (defaultSink == null) {
log.error("Default endpoint could not be created, auditlog will not work properly.");
return;
}
allSinks.put(DEFAULTSINK_NAME, defaultSink);
// create all other sinks
Map sinkSettingsMap = Utils.convertJsonToxToStructuredMap(settings.getAsSettings(ConfigConstants.SEARCHGUARD_AUDIT_CONFIG_ENDPOINTS));
for (Entry sinkEntry : sinkSettingsMap.entrySet()) {
String sinkName = sinkEntry.getKey();
// do not create fallback twice
if(sinkName.equalsIgnoreCase(FALLBACKSINK_NAME)) {
continue;
}
String type = settings.getAsSettings(ConfigConstants.SEARCHGUARD_AUDIT_CONFIG_ENDPOINTS + "." + sinkName).get("type");
if (type == null) {
log.error("No type defined for endpoint {}.", sinkName);
continue;
}
AuditLogSink sink = createSink(sinkName, type, this.settings, ConfigConstants.SEARCHGUARD_AUDIT_CONFIG_ENDPOINTS + "." + sinkName + ".config");
if (sink == null) {
log.error("Endpoint '{}' could not be created, check log file for further information.", sinkName);
continue;
}
allSinks.put(sinkName.toLowerCase(), sink);
if (log.isDebugEnabled()) {
log.debug("sink '{}' created successfully.", sinkName);
}
}
}
public AuditLogSink getSink(String sinkName) {
return allSinks.get(sinkName.toLowerCase());
}
public AuditLogSink getDefaultSink() {
return defaultSink;
}
public void close() {
for (AuditLogSink sink : allSinks.values()) {
close(sink);
}
}
protected void close(AuditLogSink sink) {
try {
log.info("Closing {}", sink.getClass().getSimpleName());
sink.close();
} catch (Exception ex) {
log.info("Could not close sink '{}' due to '{}'", sink.getClass().getSimpleName(), ex.getMessage());
}
}
private final AuditLogSink createSink(final String name, final String type, final Settings settings, final String settingsPrefix) {
AuditLogSink sink = null;
if (type != null) {
switch (type.toLowerCase()) {
case "internal_elasticsearch":
sink = new InternalESSink(name, settings, settingsPrefix, configPath, clientProvider, threadPool, fallbackSink);
break;
case "external_elasticsearch":
try {
sink = new ExternalESSink(name, settings, settingsPrefix, configPath, fallbackSink);
} catch (Exception e) {
log.error("Audit logging unavailable: Unable to setup HttpESAuditLog due to", e);
}
break;
case "webhook":
try {
sink = new WebhookSink(name, settings, settingsPrefix, configPath, fallbackSink);
} catch (Exception e1) {
log.error("Audit logging unavailable: Unable to setup WebhookAuditLog due to", e1);
}
break;
case "debug":
sink = new DebugSink(name, settings, fallbackSink);
break;
case "noop":
sink = new NoopSink(name, settings, fallbackSink);
break;
case "log4j":
sink = new Log4JSink(name, settings, settingsPrefix, fallbackSink);
break;
case "kafka":
sink = new KafkaSink(name, settings, settingsPrefix, fallbackSink);
break;
default:
try {
Class> delegateClass = Class.forName(type);
if (AuditLogSink.class.isAssignableFrom(delegateClass)) {
try {
sink = (AuditLogSink) delegateClass.getConstructor(String.class, Settings.class, String.class, Path.class, Client.class, ThreadPool.class, AuditLogSink.class).newInstance(name, settings, settingsPrefix, configPath,
clientProvider, threadPool, fallbackSink);
} catch (Throwable e) {
sink = (AuditLogSink) delegateClass.getConstructor(String.class, Settings.class, String.class, AuditLogSink.class).newInstance(name, settings, settingsPrefix, fallbackSink);
}
} else {
log.error("Audit logging unavailable: '{}' is not a subclass of {}", type, AuditLogSink.class.getSimpleName());
}
} catch (Throwable e) { // we need really catch a Throwable here!
log.error("Audit logging unavailable: Cannot instantiate object of class {} due to ", type, e);
}
}
}
return sink;
}
}