diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java index faeaeebfee5..0a0af76b4ee 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/Security.java @@ -11,14 +11,19 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.support.ActionFilter; +import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Strings; import org.elasticsearch.common.component.LifecycleComponent; @@ -63,12 +68,12 @@ import org.elasticsearch.xpack.security.action.user.TransportChangePasswordActio import org.elasticsearch.xpack.security.action.user.TransportDeleteUserAction; import org.elasticsearch.xpack.security.action.user.TransportGetUsersAction; import org.elasticsearch.xpack.security.action.user.TransportPutUserAction; -import org.elasticsearch.xpack.security.audit.AuditTrailModule; +import org.elasticsearch.xpack.security.audit.AuditTrail; +import org.elasticsearch.xpack.security.audit.AuditTrailService; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; import org.elasticsearch.xpack.security.audit.index.IndexNameResolver; -import org.elasticsearch.xpack.security.authc.AuthenticationFailureHandler; +import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; import org.elasticsearch.xpack.security.authc.AuthenticationModule; -import org.elasticsearch.xpack.security.authc.DefaultAuthenticationFailureHandler; import org.elasticsearch.xpack.security.authc.InternalAuthenticationService; import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.Realms; @@ -128,6 +133,14 @@ public class Security implements ActionPlugin { public static final String DLS_FLS_FEATURE = "security.dls_fls"; public static final Setting> USER_SETTING = OptionalSettings.createString(setting("user"), Property.NodeScope); + public static final Setting AUDIT_ENABLED_SETTING = + Setting.boolSetting(featureEnabledSetting("audit"), false, Property.NodeScope); + public static final Setting> AUDIT_OUTPUTS_SETTING = + Setting.listSetting(setting("audit.outputs"), + s -> s.getAsMap().containsKey(setting("audit.outputs")) ? + Collections.emptyList() : Collections.singletonList(LoggingAuditTrail.NAME), + Function.identity(), Property.NodeScope); + private final Settings settings; private final Environment env; private final boolean enabled; @@ -182,10 +195,17 @@ public class Security implements ActionPlugin { modules.add(new AuthenticationModule(settings)); modules.add(new AuthorizationModule(settings)); + if (enabled == false || auditingEnabled(settings) == false) { + modules.add(b -> { + b.bind(AuditTrailService.class).toProvider(Providers.of(null)); + b.bind(AuditTrail.class).toInstance(AuditTrail.NOOP); + }); + } if (enabled == false) { - modules.add(b -> b.bind(CryptoService.class).toProvider(Providers.of(null))); + modules.add(b -> { + b.bind(CryptoService.class).toProvider(Providers.of(null)); + }); modules.add(new SecurityModule(settings)); - modules.add(new AuditTrailModule(settings)); modules.add(new SecurityTransportModule(settings)); return modules; } @@ -193,10 +213,16 @@ public class Security implements ActionPlugin { // we can't load that at construction time since the license plugin might not have been loaded at that point // which might not be the case during Plugin class instantiation. Once nodeModules are pulled // everything should have been loaded - - modules.add(b -> b.bind(CryptoService.class).toInstance(cryptoService)); + modules.add(b -> { + b.bind(CryptoService.class).toInstance(cryptoService); + if (auditingEnabled(settings)) { + b.bind(AuditTrail.class).to(AuditTrailService.class); // interface used by some actions... + } else { + // TODO: remove this once we can construct SecurityLifecycleService without guice + b.bind(IndexAuditTrail.class).toProvider(Providers.of(null)); + } + }); modules.add(new SecurityModule(settings)); - modules.add(new AuditTrailModule(settings)); modules.add(new SecurityRestModule(settings)); modules.add(new SecurityActionModule(settings)); modules.add(new SecurityTransportModule(settings)); @@ -212,15 +238,18 @@ public class Security implements ActionPlugin { return list; } - public Collection createComponents(InternalClient client, ThreadPool threadPool, + public Collection createComponents(InternalClient client, ThreadPool threadPool, ClusterService clusterService, ResourceWatcherService resourceWatcherService, List extensions) { if (enabled == false) { return Collections.emptyList(); } + List components = new ArrayList<>(); final SSLConfiguration.Global globalSslConfig = new SSLConfiguration.Global(settings); final ClientSSLService clientSSLService = new ClientSSLService(settings, env, globalSslConfig, resourceWatcherService); final ServerSSLService serverSSLService = new ServerSSLService(settings, env, globalSslConfig, resourceWatcherService); + components.add(clientSSLService); + components.add(serverSSLService); // realms construction final NativeUsersStore nativeUsersStore = new NativeUsersStore(settings, client, threadPool); @@ -241,8 +270,33 @@ public class Security implements ActionPlugin { } } final Realms realms = new Realms(settings, env, realmFactories, securityLicenseState, reservedRealm); + components.add(nativeUsersStore); + components.add(realms); - return Arrays.asList(clientSSLService, serverSSLService, nativeUsersStore, realms); + // audit trails construction + if (AUDIT_ENABLED_SETTING.get(settings)) { + List outputs = AUDIT_OUTPUTS_SETTING.get(settings); + if (outputs.isEmpty()) { + throw new IllegalArgumentException("Audit logging is enabled but there are zero output types in " + + AUDIT_ENABLED_SETTING.getKey()); + } + Set auditTrails = new LinkedHashSet<>(); + for (String output : outputs) { + switch (output) { + case LoggingAuditTrail.NAME: + auditTrails.add(new LoggingAuditTrail(settings, clusterService, threadPool)); + break; + case IndexAuditTrail.NAME: + auditTrails.add(new IndexAuditTrail(settings, client, threadPool, clusterService)); + break; + default: + throw new IllegalArgumentException("Unknown audit trail output [" + output + "]"); + } + } + components.add(new AuditTrailService(settings, auditTrails.stream().collect(Collectors.toList()), securityLicenseState)); + } + + return components; } public Settings additionalSettings() { @@ -288,7 +342,10 @@ public class Security implements ActionPlugin { IPFilter.addSettings(settingsList); // audit settings - AuditTrailModule.addSettings(settingsList); + settingsList.add(AUDIT_ENABLED_SETTING); + settingsList.add(AUDIT_OUTPUTS_SETTING); + LoggingAuditTrail.registerSettings(settingsList); + IndexAuditTrail.registerSettings(settingsList); // authentication settings FileRolesStore.addSettings(settingsList); @@ -515,13 +572,29 @@ public class Security implements ActionPlugin { return XPackPlugin.featureEnabledSetting("security." + feature); } + public static boolean auditingEnabled(Settings settings) { + return AUDIT_ENABLED_SETTING.get(settings); + } + + public static boolean indexAuditLoggingEnabled(Settings settings) { + if (auditingEnabled(settings)) { + List outputs = AUDIT_OUTPUTS_SETTING.get(settings); + for (String output : outputs) { + if (output.equals(IndexAuditTrail.NAME)) { + return true; + } + } + } + return false; + } + static void validateAutoCreateIndex(Settings settings) { String value = settings.get("action.auto_create_index"); if (value == null) { return; } - final boolean indexAuditingEnabled = AuditTrailModule.indexAuditLoggingEnabled(settings); + final boolean indexAuditingEnabled = Security.indexAuditLoggingEnabled(settings); final String auditIndex = indexAuditingEnabled ? "," + IndexAuditTrail.INDEX_NAME_PREFIX + "*" : ""; String errorMessage = LoggerMessageFormat.format("the [action.auto_create_index] setting value [{}] is too" + " restrictive. disable [action.auto_create_index] or set it to " + diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java index 8fd9f297741..a43c5e6872f 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/SecurityLifecycleService.java @@ -11,10 +11,8 @@ import org.elasticsearch.cluster.ClusterStateListener; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.LifecycleListener; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.common.inject.Provider; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; -import org.elasticsearch.xpack.security.audit.AuditTrailModule; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore; import org.elasticsearch.xpack.security.authz.store.NativeRolesStore; @@ -111,7 +109,7 @@ public class SecurityLifecycleService extends AbstractComponent implements Clust } try { - if (AuditTrailModule.indexAuditLoggingEnabled(settings) && + if (Security.indexAuditLoggingEnabled(settings) && indexAuditTrail.state() == IndexAuditTrail.State.INITIALIZED) { if (indexAuditTrail.canStart(event, master)) { threadPool.generic().execute(new AbstractRunnable() { diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailModule.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailModule.java deleted file mode 100644 index bee3c2d716d..00000000000 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailModule.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.security.audit; - -import org.elasticsearch.ElasticsearchException; -import org.elasticsearch.common.inject.multibindings.Multibinder; -import org.elasticsearch.common.inject.util.Providers; -import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Setting.Property; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.util.set.Sets; -import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; -import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; -import org.elasticsearch.xpack.security.support.AbstractSecurityModule; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.function.Function; - -import static org.elasticsearch.xpack.security.Security.featureEnabledSetting; -import static org.elasticsearch.xpack.security.Security.setting; - -/** - * - */ -public class AuditTrailModule extends AbstractSecurityModule.Node { - - public static final Setting ENABLED_SETTING = - Setting.boolSetting(featureEnabledSetting("audit"), false, Property.NodeScope); - public static final Setting> OUTPUTS_SETTING = - Setting.listSetting(setting("audit.outputs"), - s -> s.getAsMap().containsKey(setting("audit.outputs")) ? - Collections.emptyList() : Collections.singletonList(LoggingAuditTrail.NAME), - Function.identity(), Property.NodeScope); - private final boolean enabled; - - public AuditTrailModule(Settings settings) { - super(settings); - enabled = ENABLED_SETTING.get(settings); - } - - @Override - protected void configureNode() { - List outputs = OUTPUTS_SETTING.get(settings); - if (securityEnabled == false || enabled == false || outputs.isEmpty()) { - bind(AuditTrailService.class).toProvider(Providers.of(null)); - bind(AuditTrail.class).toInstance(AuditTrail.NOOP); - return; - } - - bind(AuditTrailService.class).asEagerSingleton(); - bind(AuditTrail.class).to(AuditTrailService.class); - Multibinder binder = Multibinder.newSetBinder(binder(), AuditTrail.class); - for (String output : outputs) { - switch (output) { - case LoggingAuditTrail.NAME: - binder.addBinding().to(LoggingAuditTrail.class); - bind(LoggingAuditTrail.class).asEagerSingleton(); - break; - case IndexAuditTrail.NAME: - binder.addBinding().to(IndexAuditTrail.class); - bind(IndexAuditTrail.class).asEagerSingleton(); - break; - default: - throw new IllegalArgumentException("unknown audit trail output [" + output + "]"); - } - } - } - - public static boolean auditingEnabled(Settings settings) { - return ENABLED_SETTING.get(settings); - } - - public static boolean indexAuditLoggingEnabled(Settings settings) { - if (auditingEnabled(settings)) { - List outputs = OUTPUTS_SETTING.get(settings); - for (String output : outputs) { - if (output.equals(IndexAuditTrail.NAME)) { - return true; - } - } - } - return false; - } - - public static boolean fileAuditLoggingEnabled(Settings settings) { - if (auditingEnabled(settings)) { - List outputs = OUTPUTS_SETTING.get(settings); - for (String output : outputs) { - if (output.equals(LoggingAuditTrail.NAME)) { - return true; - } - } - } - return false; - } - - public static void addSettings(List> settings) { - settings.add(ENABLED_SETTING); - settings.add(OUTPUTS_SETTING); - LoggingAuditTrail.registerSettings(settings); - IndexAuditTrail.registerSettings(settings); - } -} diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java index 87e1e50ee40..60a8307443d 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/AuditTrailService.java @@ -5,20 +5,23 @@ */ package org.elasticsearch.xpack.security.audit; +import java.net.InetAddress; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.transport.TransportMessage; +import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.SecurityLicenseState; -import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.xpack.security.authc.AuthenticationToken; import org.elasticsearch.xpack.security.transport.filter.SecurityIpFilterRule; -import org.elasticsearch.transport.TransportMessage; - -import java.net.InetAddress; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; +import org.elasticsearch.xpack.security.user.User; /** * @@ -26,20 +29,24 @@ import java.util.Set; public class AuditTrailService extends AbstractComponent implements AuditTrail { private final SecurityLicenseState securityLicenseState; - final AuditTrail[] auditTrails; + final List auditTrails; @Override public String name() { return "service"; } - @Inject - public AuditTrailService(Settings settings, Set auditTrails, SecurityLicenseState licenseState) { + public AuditTrailService(Settings settings, List auditTrails, SecurityLicenseState licenseState) { super(settings); - this.auditTrails = auditTrails.toArray(new AuditTrail[auditTrails.size()]); + this.auditTrails = Collections.unmodifiableList(auditTrails); this.securityLicenseState = licenseState; } + /** Returns the audit trail implementations that this service delegates to. */ + public List getAuditTrails() { + return auditTrails; + } + @Override public void anonymousAccessDenied(String action, TransportMessage message) { if (securityLicenseState.auditingEnabled()) { @@ -202,8 +209,8 @@ public class AuditTrailService extends AbstractComponent implements AuditTrail { public Map usageStats() { Map map = new HashMap<>(2); - map.put("enabled", AuditTrailModule.ENABLED_SETTING.get(settings)); - map.put("outputs", AuditTrailModule.OUTPUTS_SETTING.get(settings)); + map.put("enabled", Security.AUDIT_ENABLED_SETTING.get(settings)); + map.put("outputs", Security.AUDIT_OUTPUTS_SETTING.get(settings)); return map; } } diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java index 329c20777ed..d254a67b517 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/index/IndexAuditTrail.java @@ -169,9 +169,7 @@ public class IndexAuditTrail extends AbstractComponent implements AuditTrail, Cl return NAME; } - @Inject - public IndexAuditTrail(Settings settings, InternalClient client, ThreadPool threadPool, - ClusterService clusterService) { + public IndexAuditTrail(Settings settings, InternalClient client, ThreadPool threadPool, ClusterService clusterService) { super(settings); this.threadPool = threadPool; this.clusterService = clusterService; diff --git a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java index 209c87598dd..2b74749b5fd 100644 --- a/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java +++ b/elasticsearch/x-pack/security/src/main/java/org/elasticsearch/xpack/security/audit/logfile/LoggingAuditTrail.java @@ -68,7 +68,6 @@ public class LoggingAuditTrail extends AbstractComponent implements AuditTrail { return NAME; } - @Inject public LoggingAuditTrail(Settings settings, ClusterService clusterService, ThreadPool threadPool) { this(settings, clusterService, Loggers.getLogger(LoggingAuditTrail.class), threadPool.getThreadContext()); } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index b23717f8dd8..eb2990b7691 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -18,7 +18,6 @@ import org.elasticsearch.test.ESIntegTestCase.Scope; import org.elasticsearch.xpack.security.authc.file.FileRealm; import org.elasticsearch.xpack.security.authc.esnative.NativeRealm; import org.elasticsearch.xpack.security.Security; -import org.elasticsearch.xpack.security.audit.AuditTrailModule; import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.SecuredString; @@ -129,7 +128,7 @@ public class SecuritySettingsSource extends ClusterDiscoveryConfiguration.Unicas //TODO: for now isolate security tests from watcher & monitoring (randomize this later) .put(XPackPlugin.featureEnabledSetting(Watcher.NAME), false) .put(XPackPlugin.featureEnabledSetting(Monitoring.NAME), false) - .put(AuditTrailModule.ENABLED_SETTING.getKey(), randomBoolean()) + .put(Security.AUDIT_ENABLED_SETTING.getKey(), randomBoolean()) .put(LoggingAuditTrail.HOST_ADDRESS_SETTING.getKey(), randomBoolean()) .put(LoggingAuditTrail.HOST_NAME_SETTING.getKey(), randomBoolean()) .put(LoggingAuditTrail.NODE_NAME_SETTING.getKey(), randomBoolean()) diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecuritySettingsTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecuritySettingsTests.java index daffe7a159e..e5e71fb5539 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecuritySettingsTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecuritySettingsTests.java @@ -9,8 +9,6 @@ import java.io.IOException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.env.Environment; -import org.elasticsearch.xpack.security.audit.AuditTrailModule; import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.XPackPlugin; @@ -159,14 +157,14 @@ public class SecuritySettingsTests extends ESTestCase { Security.validateAutoCreateIndex(Settings.builder() .put("action.auto_create_index", ".security") - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) .build()); try { Security.validateAutoCreateIndex(Settings.builder() .put("action.auto_create_index", ".security") - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) - .put(AuditTrailModule.OUTPUTS_SETTING.getKey(), randomFrom("index", "logfile,index")) + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_OUTPUTS_SETTING.getKey(), randomFrom("index", "logfile,index")) .build()); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) { @@ -176,8 +174,8 @@ public class SecuritySettingsTests extends ESTestCase { Security.validateAutoCreateIndex(Settings.builder() .put("action.auto_create_index", ".security_audit_log*,.security") - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) - .put(AuditTrailModule.OUTPUTS_SETTING.getKey(), randomFrom("index", "logfile,index")) + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_OUTPUTS_SETTING.getKey(), randomFrom("index", "logfile,index")) .build()); } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java index 784f9e214b9..ce39eaa4ca3 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/SecurityTests.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import org.elasticsearch.common.settings.Settings; @@ -16,6 +17,10 @@ import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.extensions.XPackExtension; +import org.elasticsearch.xpack.security.audit.AuditTrail; +import org.elasticsearch.xpack.security.audit.AuditTrailService; +import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; +import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.Realms; import org.elasticsearch.xpack.security.authc.file.FileRealm; @@ -49,7 +54,7 @@ public class SecurityTests extends ESTestCase { Environment env = new Environment(settings); Security security = new Security(settings, env); ThreadPool threadPool = mock(ThreadPool.class); - return security.createComponents(null, threadPool, null, Arrays.asList(extensions)); + return security.createComponents(null, threadPool, null, null, Arrays.asList(extensions)); } private T findComponent(Class type, Collection components) { @@ -58,12 +63,13 @@ public class SecurityTests extends ESTestCase { return type.cast(obj); } } - throw new AssertionError("Could not find component of type " + type + " in components"); + return null; } public void testCustomRealmExtension() throws Exception { Collection components = createComponents(Settings.EMPTY, new DummyExtension("myrealm")); Realms realms = findComponent(Realms.class, components); + assertNotNull(realms); assertNotNull(realms.realmFactory("myrealm")); } @@ -72,4 +78,50 @@ public class SecurityTests extends ESTestCase { () -> createComponents(Settings.EMPTY, new DummyExtension(FileRealm.TYPE))); assertEquals("Realm type [" + FileRealm.TYPE + "] is already registered", e.getMessage()); } + + + public void testAuditEnabled() throws Exception { + Settings settings = Settings.builder().put(Security.AUDIT_ENABLED_SETTING.getKey(), true).build(); + Collection components = createComponents(settings); + AuditTrailService service = findComponent(AuditTrailService.class, components); + assertNotNull(service); + assertEquals(1, service.getAuditTrails().size()); + assertEquals(LoggingAuditTrail.NAME, service.getAuditTrails().get(0).name()); + } + + public void testDisabledByDefault() throws Exception { + Collection components = createComponents(Settings.EMPTY); + assertNull(findComponent(AuditTrailService.class, components)); + } + + public void testIndexAuditTrail() throws Exception { + Settings settings = Settings.builder() + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index").build(); + Collection components = createComponents(settings); + AuditTrailService service = findComponent(AuditTrailService.class, components); + assertNotNull(service); + assertEquals(1, service.getAuditTrails().size()); + assertEquals(IndexAuditTrail.NAME, service.getAuditTrails().get(0).name()); + } + + public void testIndexAndLoggingAuditTrail() throws Exception { + Settings settings = Settings.builder() + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "index,logfile").build(); + Collection components = createComponents(settings); + AuditTrailService service = findComponent(AuditTrailService.class, components); + assertNotNull(service); + assertEquals(2, service.getAuditTrails().size()); + assertEquals(IndexAuditTrail.NAME, service.getAuditTrails().get(0).name()); + assertEquals(LoggingAuditTrail.NAME, service.getAuditTrails().get(1).name()); + } + + public void testUnknownOutput() throws Exception { + Settings settings = Settings.builder() + .put(Security.AUDIT_ENABLED_SETTING.getKey(), true) + .put(Security.AUDIT_OUTPUTS_SETTING.getKey(), "foo").build(); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> createComponents(settings)); + assertEquals("Unknown audit trail output [foo]", e.getMessage()); + } } diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailModuleTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailModuleTests.java deleted file mode 100644 index 4a5f9871bdc..00000000000 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailModuleTests.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -package org.elasticsearch.xpack.security.audit; - -import org.elasticsearch.common.inject.ModuleTestCase; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail; -import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail; - -public class AuditTrailModuleTests extends ModuleTestCase { - - public void testEnabled() throws Exception { - Settings settings = Settings.builder().put(AuditTrailModule.ENABLED_SETTING.getKey(), true).build(); - AuditTrailModule module = new AuditTrailModule(settings); - assertBinding(module, AuditTrail.class, AuditTrailService.class); - assertSetMultiBinding(module, AuditTrail.class, LoggingAuditTrail.class); - } - - public void testDisabledByDefault() throws Exception { - AuditTrailModule module = new AuditTrailModule(Settings.EMPTY); - assertInstanceBinding(module, AuditTrail.class, x -> x == AuditTrail.NOOP); - } - - public void testIndexAuditTrail() throws Exception { - Settings settings = Settings.builder() - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) - .put(AuditTrailModule.OUTPUTS_SETTING.getKey(), "index").build(); - AuditTrailModule module = new AuditTrailModule(settings); - assertSetMultiBinding(module, AuditTrail.class, IndexAuditTrail.class); - } - - public void testIndexAndLoggingAuditTrail() throws Exception { - Settings settings = Settings.builder() - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) - .put(AuditTrailModule.OUTPUTS_SETTING.getKey(), "index,logfile").build(); - AuditTrailModule module = new AuditTrailModule(settings); - assertSetMultiBinding(module, AuditTrail.class, IndexAuditTrail.class, LoggingAuditTrail.class); - } - - public void testUnknownOutput() throws Exception { - Settings settings = Settings.builder() - .put(AuditTrailModule.ENABLED_SETTING.getKey(), true) - .put(AuditTrailModule.OUTPUTS_SETTING.getKey(), "foo").build(); - AuditTrailModule module = new AuditTrailModule(settings); - assertBindingFailure(module, "unknown audit trail output [foo]"); - } -} diff --git a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java index cfcd031d0a4..27b225d3c42 100644 --- a/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java +++ b/elasticsearch/x-pack/security/src/test/java/org/elasticsearch/xpack/security/audit/AuditTrailServiceTests.java @@ -17,10 +17,12 @@ import org.elasticsearch.transport.TransportMessage; import org.junit.Before; import java.net.InetAddress; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; -import static java.util.Collections.unmodifiableSet; +import static java.util.Collections.unmodifiableList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -30,7 +32,7 @@ import static org.mockito.Mockito.when; * */ public class AuditTrailServiceTests extends ESTestCase { - private Set auditTrails; + private List auditTrails; private AuditTrailService service; private AuthenticationToken token; @@ -41,11 +43,11 @@ public class AuditTrailServiceTests extends ESTestCase { @Before public void init() throws Exception { - Set auditTrailsBuilder = new HashSet<>(); + List auditTrailsBuilder = new ArrayList<>(); for (int i = 0; i < randomIntBetween(1, 4); i++) { auditTrailsBuilder.add(mock(AuditTrail.class)); } - auditTrails = unmodifiableSet(auditTrailsBuilder); + auditTrails = unmodifiableList(auditTrailsBuilder); securityLicenseState = mock(SecurityLicenseState.class); service = new AuditTrailService(Settings.EMPTY, auditTrails, securityLicenseState); auditingEnabled = randomBoolean(); diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java index f078d1fb1c9..cfde23af6d6 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/XPackPlugin.java @@ -192,7 +192,8 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin { components.addAll(licensing.createComponents(clusterService, getClock(), env, resourceWatcherService, security.getSecurityLicenseState())); - components.addAll(security.createComponents(internalClient, threadPool, resourceWatcherService, extensionsService.getExtensions())); + components.addAll(security.createComponents(internalClient, threadPool, clusterService, resourceWatcherService, + extensionsService.getExtensions())); // watcher http stuff Map httpAuthFactories = new HashMap<>();