diff --git a/src/main/java/org/elasticsearch/shield/SecurityFilterModule.java b/src/main/java/org/elasticsearch/shield/SecurityFilterModule.java index 6cce786a6b2..a436bc1c2af 100644 --- a/src/main/java/org/elasticsearch/shield/SecurityFilterModule.java +++ b/src/main/java/org/elasticsearch/shield/SecurityFilterModule.java @@ -5,15 +5,20 @@ */ package org.elasticsearch.shield; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.shield.support.AbstractShieldModule; /** * */ -public class SecurityFilterModule extends AbstractModule { +public class SecurityFilterModule extends AbstractShieldModule.Node { + + public SecurityFilterModule(Settings settings) { + super(settings); + } @Override - protected void configure() { + protected void configureNode() { bind(SecurityFilter.class).asEagerSingleton(); } } diff --git a/src/main/java/org/elasticsearch/shield/SecurityException.java b/src/main/java/org/elasticsearch/shield/ShieldException.java similarity index 72% rename from src/main/java/org/elasticsearch/shield/SecurityException.java rename to src/main/java/org/elasticsearch/shield/ShieldException.java index 722d6340061..4f1eb8ac8d8 100644 --- a/src/main/java/org/elasticsearch/shield/SecurityException.java +++ b/src/main/java/org/elasticsearch/shield/ShieldException.java @@ -9,24 +9,24 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.Lists; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import java.util.List; /** * */ -public class SecurityException extends ElasticsearchException.WithRestHeaders { +public class ShieldException extends ElasticsearchException.WithRestHeaders { public static final ImmutableMap> HEADERS = ImmutableMap.>builder() - .put("WWW-Authenticate", Lists.newArrayList("Basic realm=\""+ SecurityPlugin.NAME +"\"")) + .put("WWW-Authenticate", Lists.newArrayList("Basic realm=\""+ ShieldPlugin.NAME +"\"")) .build(); - public SecurityException(String msg) { + public ShieldException(String msg) { super(msg, HEADERS); } - public SecurityException(String msg, Throwable cause) { + public ShieldException(String msg, Throwable cause) { super(msg, cause, HEADERS); } } diff --git a/src/main/java/org/elasticsearch/shield/SecurityModule.java b/src/main/java/org/elasticsearch/shield/ShieldModule.java similarity index 56% rename from src/main/java/org/elasticsearch/shield/SecurityModule.java rename to src/main/java/org/elasticsearch/shield/ShieldModule.java index 10d887e1747..4d2cc15539c 100644 --- a/src/main/java/org/elasticsearch/shield/SecurityModule.java +++ b/src/main/java/org/elasticsearch/shield/ShieldModule.java @@ -7,61 +7,60 @@ package org.elasticsearch.shield; import org.elasticsearch.action.ActionModule; import org.elasticsearch.common.collect.ImmutableList; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.PreProcessModule; -import org.elasticsearch.common.inject.SpawnModules; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.audit.AuditTrailModule; import org.elasticsearch.shield.authc.AuthenticationModule; import org.elasticsearch.shield.authz.AuthorizationModule; +import org.elasticsearch.shield.support.AbstractShieldModule; import org.elasticsearch.shield.transport.SecuredRestModule; import org.elasticsearch.shield.transport.SecuredTransportModule; /** * */ -public class SecurityModule extends AbstractModule implements SpawnModules, PreProcessModule { +public class ShieldModule extends AbstractShieldModule.Spawn implements PreProcessModule { - private final Settings settings; - private final boolean isClient; - private final boolean isShieldEnabled; + private final boolean enabled; - public SecurityModule(Settings settings) { - this.settings = settings; - this.isClient = settings.getAsBoolean("node.client", false); - this.isShieldEnabled = settings.getAsBoolean("shield.enabled", true); + public ShieldModule(Settings settings) { + super(settings); + this.enabled = settings.getAsBoolean("shield.enabled", true); } @Override public void processModule(Module module) { - if (module instanceof ActionModule && isShieldEnabled && !isClient) { + if (module instanceof ActionModule && enabled && !clientMode) { ((ActionModule) module).registerFilter(SecurityFilter.Action.class); } } @Override - public Iterable spawnModules() { + public Iterable spawnModules(boolean clientMode) { // don't spawn modules if shield is explicitly disabled - if (!isShieldEnabled) { + if (!enabled) { return ImmutableList.of(); } // spawn needed parts in client mode - if (isClient) { - return ImmutableList.of(new SecuredTransportModule(), new SecurityFilterModule()); + if (clientMode) { + return ImmutableList.of( + new SecuredTransportModule(settings), + new SecurityFilterModule(settings)); } return ImmutableList.of( new AuthenticationModule(settings), - new AuthorizationModule(), + new AuthorizationModule(settings), new AuditTrailModule(settings), - new SecuredTransportModule(), - new SecuredRestModule(), - new SecurityFilterModule()); + new SecuredTransportModule(settings), + new SecuredRestModule(settings), + new SecurityFilterModule(settings)); } + @Override - protected void configure() { + protected void configure(boolean clientMode) { } } diff --git a/src/main/java/org/elasticsearch/shield/SecuritySettingsException.java b/src/main/java/org/elasticsearch/shield/ShieldSettingsException.java similarity index 65% rename from src/main/java/org/elasticsearch/shield/SecuritySettingsException.java rename to src/main/java/org/elasticsearch/shield/ShieldSettingsException.java index 2acae7da5d1..b47e5e89d43 100644 --- a/src/main/java/org/elasticsearch/shield/SecuritySettingsException.java +++ b/src/main/java/org/elasticsearch/shield/ShieldSettingsException.java @@ -8,13 +8,13 @@ package org.elasticsearch.shield; /** * */ -public class SecuritySettingsException extends SecurityException { +public class ShieldSettingsException extends ShieldException { - public SecuritySettingsException(String msg) { + public ShieldSettingsException(String msg) { super(msg); } - public SecuritySettingsException(String msg, Throwable cause) { + public ShieldSettingsException(String msg, Throwable cause) { super(msg, cause); } diff --git a/src/main/java/org/elasticsearch/shield/audit/AuditException.java b/src/main/java/org/elasticsearch/shield/audit/AuditException.java index 0dbf1463ed1..82a23c1271e 100644 --- a/src/main/java/org/elasticsearch/shield/audit/AuditException.java +++ b/src/main/java/org/elasticsearch/shield/audit/AuditException.java @@ -5,10 +5,12 @@ */ package org.elasticsearch.shield.audit; +import org.elasticsearch.shield.ShieldException; + /** * */ -public class AuditException extends org.elasticsearch.shield.SecurityException { +public class AuditException extends ShieldException { public AuditException(String msg) { super(msg); diff --git a/src/main/java/org/elasticsearch/shield/audit/AuditTrailModule.java b/src/main/java/org/elasticsearch/shield/audit/AuditTrailModule.java index 17a797697d6..5bed05df3a3 100644 --- a/src/main/java/org/elasticsearch/shield/audit/AuditTrailModule.java +++ b/src/main/java/org/elasticsearch/shield/audit/AuditTrailModule.java @@ -7,27 +7,28 @@ package org.elasticsearch.shield.audit; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.collect.Sets; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.multibindings.Multibinder; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.audit.logfile.LoggingAuditTrail; +import org.elasticsearch.shield.support.AbstractShieldModule; import java.util.Set; /** * */ -public class AuditTrailModule extends AbstractModule { +public class AuditTrailModule extends AbstractShieldModule.Node { - private final Settings settings; + private final boolean enabled; public AuditTrailModule(Settings settings) { - this.settings = settings; + super(settings); + enabled = settings.getAsBoolean("shield.audit.enabled", false); } @Override - protected void configure() { - if (!settings.getAsBoolean("shield.audit.enabled", false)) { + protected void configureNode() { + if (!enabled) { bind(AuditTrail.class).toInstance(AuditTrail.NOOP); return; } diff --git a/src/main/java/org/elasticsearch/shield/authc/AuthenticationException.java b/src/main/java/org/elasticsearch/shield/authc/AuthenticationException.java index 51dccf93785..44e5c6a1dfb 100644 --- a/src/main/java/org/elasticsearch/shield/authc/AuthenticationException.java +++ b/src/main/java/org/elasticsearch/shield/authc/AuthenticationException.java @@ -6,11 +6,12 @@ package org.elasticsearch.shield.authc; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.shield.ShieldException; /** * */ -public class AuthenticationException extends org.elasticsearch.shield.SecurityException { +public class AuthenticationException extends ShieldException { public AuthenticationException(String msg) { super(msg); diff --git a/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java b/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java index e28a7b0a80f..635e6e98e31 100644 --- a/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java +++ b/src/main/java/org/elasticsearch/shield/authc/AuthenticationModule.java @@ -6,55 +6,31 @@ package org.elasticsearch.shield.authc; import org.elasticsearch.common.collect.ImmutableList; -import org.elasticsearch.common.inject.AbstractModule; -import org.elasticsearch.common.inject.Module; -import org.elasticsearch.common.inject.SpawnModules; -import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authc.esusers.ESUsersModule; -import org.elasticsearch.shield.authc.esusers.ESUsersRealm; import org.elasticsearch.shield.authc.ldap.LdapModule; -import org.elasticsearch.shield.authc.ldap.LdapRealm; import org.elasticsearch.shield.authc.system.SystemRealm; - -import static org.elasticsearch.common.inject.name.Names.named; +import org.elasticsearch.shield.support.AbstractShieldModule; /** * */ -public class AuthenticationModule extends AbstractModule implements SpawnModules { - - private final Settings settings; - private final boolean esusersEnabled; - private final boolean ldapEnabled; +public class AuthenticationModule extends AbstractShieldModule.Node.Spawn { public AuthenticationModule(Settings settings) { - this.settings = settings; - this.esusersEnabled = ESUsersModule.enabled(settings); - this.ldapEnabled = LdapModule.enabled(settings); + super(settings); } @Override - public Iterable spawnModules() { - ImmutableList.Builder modules = ImmutableList.builder(); - modules.add(new SystemRealm.Module()); - if (esusersEnabled) { - modules.add(new ESUsersModule()); - } - if (ldapEnabled) { - modules.add(new LdapModule(settings)); - } - return modules.build(); + public Iterable spawnModules() { + return ImmutableList.of( + new SystemRealm.Module(settings), + new ESUsersModule(settings), + new LdapModule(settings)); } @Override - protected void configure() { + protected void configureNode() { bind(AuthenticationService.class).to(InternalAuthenticationService.class).asEagerSingleton(); - if (!esusersEnabled) { - bind(ESUsersRealm.class).toProvider(Providers.of((ESUsersRealm) null)); - } - if (!ldapEnabled) { - bind(LdapRealm.class).toProvider(Providers.of((LdapRealm) null)); - } } } diff --git a/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersModule.java b/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersModule.java index 6f90d167033..bfa2316ee66 100644 --- a/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersModule.java +++ b/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersModule.java @@ -5,27 +5,39 @@ */ package org.elasticsearch.shield.authc.esusers; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.support.UserPasswdStore; import org.elasticsearch.shield.authc.support.UserRolesStore; +import org.elasticsearch.shield.support.AbstractShieldModule; import static org.elasticsearch.common.inject.name.Names.named; /** * */ -public class ESUsersModule extends AbstractModule { +public class ESUsersModule extends AbstractShieldModule.Node { - public static boolean enabled(Settings settings) { - return settings.getComponentSettings(ESUsersModule.class).getAsBoolean("enabled", true); + private final boolean enabled; + + public ESUsersModule(Settings settings) { + super(settings); + enabled = enabled(settings); } @Override - protected void configure() { - bind(Realm.class).annotatedWith(named(ESUsersRealm.TYPE)).to(ESUsersRealm.class).asEagerSingleton(); - bind(UserPasswdStore.class).annotatedWith(named("file")).to(FileUserPasswdStore.class).asEagerSingleton(); - bind(UserRolesStore.class).annotatedWith(named("file")).to(FileUserRolesStore.class).asEagerSingleton(); + protected void configureNode() { + if (enabled) { + bind(Realm.class).annotatedWith(named(ESUsersRealm.TYPE)).to(ESUsersRealm.class).asEagerSingleton(); + bind(UserPasswdStore.class).annotatedWith(named("file")).to(FileUserPasswdStore.class).asEagerSingleton(); + bind(UserRolesStore.class).annotatedWith(named("file")).to(FileUserRolesStore.class).asEagerSingleton(); + } else { + bind(ESUsersRealm.class).toProvider(Providers.of(null)); + } + } + + static boolean enabled(Settings settings) { + return settings.getComponentSettings(ESUsersModule.class).getAsBoolean("enabled", true); } } diff --git a/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java b/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java index 20cfbeeb1bf..151db907706 100644 --- a/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java +++ b/src/main/java/org/elasticsearch/shield/authc/esusers/ESUsersRealm.java @@ -10,7 +10,7 @@ import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.name.Named; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationToken; @@ -25,20 +25,18 @@ import org.elasticsearch.transport.TransportMessage; */ public class ESUsersRealm extends AbstractComponent implements Realm { - static { - BaseRestHandler.addUsefulHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); - } - public static final String TYPE = "esusers"; final UserPasswdStore userPasswdStore; final UserRolesStore userRolesStore; @Inject - public ESUsersRealm(Settings settings, @Named("file") UserPasswdStore userPasswdStore, @Named("file") UserRolesStore userRolesStore) { + public ESUsersRealm(Settings settings, @Named("file") UserPasswdStore userPasswdStore, + @Named("file") UserRolesStore userRolesStore, RestController restController) { super(settings); this.userPasswdStore = userPasswdStore; this.userRolesStore = userRolesStore; + restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); } @Override diff --git a/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStore.java b/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStore.java index 85b7e7f38f3..897f2e2bbfd 100644 --- a/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStore.java +++ b/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserPasswdStore.java @@ -16,7 +16,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.shield.authc.support.Hasher; import org.elasticsearch.shield.authc.support.UserPasswdStore; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; @@ -75,8 +75,7 @@ public class FileUserPasswdStore extends AbstractComponent implements UserPasswd public static Path resolveFile(Settings settings, Environment env) { String location = settings.get("shield.authc.esusers.files.users"); if (location == null) { - File shieldDirectory = new File(env.configFile(), SecurityPlugin.NAME); - return shieldDirectory.toPath().resolve(".users"); + return ShieldPlugin.resolveConfigFile(env, ".users"); } return Paths.get(location); } diff --git a/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserRolesStore.java b/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserRolesStore.java index ea08e509fc8..41fb59e52e7 100644 --- a/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserRolesStore.java +++ b/src/main/java/org/elasticsearch/shield/authc/esusers/FileUserRolesStore.java @@ -16,7 +16,7 @@ import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.shield.authc.support.UserRolesStore; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; @@ -68,8 +68,7 @@ public class FileUserRolesStore extends AbstractComponent implements UserRolesSt public static Path resolveFile(Settings settings, Environment env) { String location = settings.get("shield.authc.esusers.files.users_roles"); if (location == null) { - File shieldDirectory = new File(env.configFile(), SecurityPlugin.NAME); - return shieldDirectory.toPath().resolve(".users_roles"); + return ShieldPlugin.resolveConfigFile(env, ".users_roles"); } return Paths.get(location); } diff --git a/src/main/java/org/elasticsearch/shield/authc/ldap/ActiveDirectoryConnectionFactory.java b/src/main/java/org/elasticsearch/shield/authc/ldap/ActiveDirectoryConnectionFactory.java index cdcf59630ea..a3c3956170d 100644 --- a/src/main/java/org/elasticsearch/shield/authc/ldap/ActiveDirectoryConnectionFactory.java +++ b/src/main/java/org/elasticsearch/shield/authc/ldap/ActiveDirectoryConnectionFactory.java @@ -10,6 +10,7 @@ import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.shield.ShieldException; import javax.naming.Context; import javax.naming.NamingEnumeration; @@ -42,7 +43,7 @@ public class ActiveDirectoryConnectionFactory extends AbstractComponent implemen super(settings); domainName = componentSettings.get(AD_DOMAIN_NAME_SETTING); if (domainName == null) { - throw new org.elasticsearch.shield.SecurityException("Missing [" + AD_DOMAIN_NAME_SETTING + "] setting for active directory"); + throw new ShieldException("Missing [" + AD_DOMAIN_NAME_SETTING + "] setting for active directory"); } userSearchDN = componentSettings.get(AD_USER_SEARCH_BASEDN_SETTING, buildDnFromDomain(domainName)); int port = componentSettings.getAsInt(AD_PORT, 389); diff --git a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapGroupToRoleMapper.java b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapGroupToRoleMapper.java index 2d98262073d..497eedd3849 100644 --- a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapGroupToRoleMapper.java +++ b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapGroupToRoleMapper.java @@ -13,6 +13,7 @@ import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; @@ -32,7 +33,7 @@ import java.util.*; */ public class LdapGroupToRoleMapper extends AbstractComponent { - public static final String ROLE_MAPPING_DEFAULT_FILE_NAME = ".role_mapping"; + public static final String DEFAULT_FILE_NAME = ".role_mapping"; public static final String ROLE_MAPPING_FILE_SETTING = "files.role_mapping"; public static final String USE_UNMAPPED_GROUPS_AS_ROLES_SETTING = "unmapped_groups_as_roles"; @@ -57,6 +58,14 @@ public class LdapGroupToRoleMapper extends AbstractComponent { this.listener = listener; } + public static Path resolveFile(Settings settings, Environment env) { + String location = settings.get(ROLE_MAPPING_FILE_SETTING); + if (location == null) { + return ShieldPlugin.resolveConfigFile(env, DEFAULT_FILE_NAME); + } + return Paths.get(location); + } + public static ImmutableMap> parseFile(Path path, ESLogger logger) { if (!Files.exists(path)) { return ImmutableMap.of(); @@ -92,14 +101,6 @@ public class LdapGroupToRoleMapper extends AbstractComponent { } } - public static Path resolveFile(Settings settings, Environment env) { - String location = settings.get(ROLE_MAPPING_FILE_SETTING); - if (location == null) { - return env.configFile().toPath().resolve(ROLE_MAPPING_DEFAULT_FILE_NAME); - } - return Paths.get(location); - } - /** * This will map the groupDN's to ES Roles */ diff --git a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapModule.java b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapModule.java index 71e55f66354..c6f4b718e53 100644 --- a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapModule.java +++ b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapModule.java @@ -5,24 +5,42 @@ */ package org.elasticsearch.shield.authc.ldap; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.util.Providers; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.shield.authc.AuthenticationModule; import org.elasticsearch.shield.authc.Realm; +import org.elasticsearch.shield.support.AbstractShieldModule; import static org.elasticsearch.common.inject.name.Names.named; /** * Configures Ldap object injections */ -public class LdapModule extends AbstractModule { - private final Settings settings; +public class LdapModule extends AbstractShieldModule.Node { + + private final boolean enabled; public LdapModule(Settings settings) { - this.settings = settings; + super(settings); + enabled = enabled(settings); } - public static boolean enabled(Settings settings) { + @Override + protected void configureNode() { + if (enabled) { + bind(Realm.class).annotatedWith(named(LdapRealm.TYPE)).to(LdapRealm.class).asEagerSingleton(); + bind(LdapGroupToRoleMapper.class).asEagerSingleton(); + String mode = settings.getComponentSettings(LdapModule.class).get("mode", "ldap"); + if ("ldap".equals(mode)) { + bind(LdapConnectionFactory.class).to(StandardLdapConnectionFactory.class); + } else { + bind(LdapConnectionFactory.class).to(ActiveDirectoryConnectionFactory.class); + } + } else { + bind(LdapRealm.class).toProvider(Providers.of((LdapRealm) null)); + } + } + + static boolean enabled(Settings settings) { Settings authcSettings = settings.getAsSettings("shield.authc"); if (!authcSettings.names().contains("ldap")) { return false; @@ -30,16 +48,4 @@ public class LdapModule extends AbstractModule { Settings ldapSettings = authcSettings.getAsSettings("ldap"); return ldapSettings.getAsBoolean("enabled", true); } - - @Override - protected void configure() { - bind(Realm.class).annotatedWith(named(LdapRealm.TYPE)).to(LdapRealm.class).asEagerSingleton(); - bind(LdapGroupToRoleMapper.class).asEagerSingleton(); - String mode = settings.getComponentSettings(LdapModule.class).get("mode", "ldap"); - if ("ldap".equals(mode)) { - bind(LdapConnectionFactory.class).to(StandardLdapConnectionFactory.class); - } else { - bind(LdapConnectionFactory.class).to(ActiveDirectoryConnectionFactory.class); - } - } } diff --git a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java index dcdd10e9865..997b22ee6f4 100644 --- a/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java +++ b/src/main/java/org/elasticsearch/shield/authc/ldap/LdapRealm.java @@ -7,10 +7,10 @@ package org.elasticsearch.shield.authc.ldap; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.rest.BaseRestHandler; +import org.elasticsearch.rest.RestController; +import org.elasticsearch.shield.ShieldException; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationToken; -import org.elasticsearch.shield.SecurityException; import org.elasticsearch.shield.authc.Realm; import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; @@ -25,21 +25,17 @@ import java.util.Set; */ public class LdapRealm extends CachingUsernamePasswordRealm implements Realm { - static { - BaseRestHandler.addUsefulHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); - } - public static final String TYPE = "ldap"; private final LdapConnectionFactory connectionFactory; private final LdapGroupToRoleMapper roleMapper; @Inject - public LdapRealm(Settings settings, LdapConnectionFactory ldap, LdapGroupToRoleMapper roleMapper) { + public LdapRealm(Settings settings, LdapConnectionFactory ldap, LdapGroupToRoleMapper roleMapper, RestController restController) { super(settings); - this.connectionFactory = ldap; this.roleMapper = roleMapper; + restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); } @Override @@ -68,7 +64,7 @@ public class LdapRealm extends CachingUsernamePasswordRealm implements Realmbuilder() .put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory") diff --git a/src/main/java/org/elasticsearch/shield/authc/system/SystemRealm.java b/src/main/java/org/elasticsearch/shield/authc/system/SystemRealm.java index f8a5054de86..3c7024e1139 100644 --- a/src/main/java/org/elasticsearch/shield/authc/system/SystemRealm.java +++ b/src/main/java/org/elasticsearch/shield/authc/system/SystemRealm.java @@ -5,11 +5,12 @@ */ package org.elasticsearch.shield.authc.system; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.AuthenticationToken; import org.elasticsearch.shield.authc.Realm; +import org.elasticsearch.shield.support.AbstractShieldModule; import org.elasticsearch.transport.TransportMessage; /** @@ -58,9 +59,14 @@ public class SystemRealm implements Realm { return token == TOKEN ? User.SYSTEM : null; } - public static class Module extends AbstractModule { + public static class Module extends AbstractShieldModule.Node { + + public Module(Settings settings) { + super(settings); + } + @Override - protected void configure() { + protected void configureNode() { bind(SystemRealm.class).asEagerSingleton(); } } diff --git a/src/main/java/org/elasticsearch/shield/authz/AuthorizationException.java b/src/main/java/org/elasticsearch/shield/authz/AuthorizationException.java index 655eaa4142d..16ffb8e6ce9 100644 --- a/src/main/java/org/elasticsearch/shield/authz/AuthorizationException.java +++ b/src/main/java/org/elasticsearch/shield/authz/AuthorizationException.java @@ -6,11 +6,12 @@ package org.elasticsearch.shield.authz; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.shield.ShieldException; /** * */ -public class AuthorizationException extends org.elasticsearch.shield.SecurityException { +public class AuthorizationException extends ShieldException { public AuthorizationException(String msg) { super(msg); diff --git a/src/main/java/org/elasticsearch/shield/authz/AuthorizationModule.java b/src/main/java/org/elasticsearch/shield/authz/AuthorizationModule.java index eb456b8a6f7..fc3af1ee592 100644 --- a/src/main/java/org/elasticsearch/shield/authz/AuthorizationModule.java +++ b/src/main/java/org/elasticsearch/shield/authz/AuthorizationModule.java @@ -5,17 +5,22 @@ */ package org.elasticsearch.shield.authz; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.authz.store.FileRolesStore; import org.elasticsearch.shield.authz.store.RolesStore; +import org.elasticsearch.shield.support.AbstractShieldModule; /** * */ -public class AuthorizationModule extends AbstractModule { +public class AuthorizationModule extends AbstractShieldModule.Node { + + public AuthorizationModule(Settings settings) { + super(settings); + } @Override - protected void configure() { + protected void configureNode() { bind(RolesStore.class).to(FileRolesStore.class); bind(AuthorizationService.class).to(InternalAuthorizationService.class).asEagerSingleton(); } diff --git a/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java b/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java index 1aa8d4d9b58..4c0c5830a84 100644 --- a/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java +++ b/src/main/java/org/elasticsearch/shield/authz/store/FileRolesStore.java @@ -21,7 +21,7 @@ import org.elasticsearch.common.xcontent.yaml.YamlXContent; import org.elasticsearch.env.Environment; import org.elasticsearch.shield.authz.Permission; import org.elasticsearch.shield.authz.Privilege; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; @@ -74,8 +74,7 @@ public class FileRolesStore extends AbstractComponent implements RolesStore { public static Path resolveFile(Settings settings, Environment env) { String location = settings.get("files.roles"); if (location == null) { - File shieldDirectory = new File(env.configFile(), SecurityPlugin.NAME); - return shieldDirectory.toPath().resolve(".roles.yml"); + return ShieldPlugin.resolveConfigFile(env, ".roles.yml"); } return Paths.get(location); diff --git a/src/main/java/org/elasticsearch/shield/plugin/SecurityPlugin.java b/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java similarity index 60% rename from src/main/java/org/elasticsearch/shield/plugin/SecurityPlugin.java rename to src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java index f09cff24aaa..a57f4ed8fe8 100644 --- a/src/main/java/org/elasticsearch/shield/plugin/SecurityPlugin.java +++ b/src/main/java/org/elasticsearch/shield/plugin/ShieldPlugin.java @@ -7,15 +7,18 @@ package org.elasticsearch.shield.plugin; import org.elasticsearch.common.collect.ImmutableList; import org.elasticsearch.common.inject.Module; +import org.elasticsearch.env.Environment; import org.elasticsearch.plugins.AbstractPlugin; -import org.elasticsearch.shield.SecurityModule; +import org.elasticsearch.shield.ShieldModule; +import java.io.File; +import java.nio.file.Path; import java.util.Collection; /** * */ -public class SecurityPlugin extends AbstractPlugin { +public class ShieldPlugin extends AbstractPlugin { public static final String NAME = "shield"; @@ -31,7 +34,15 @@ public class SecurityPlugin extends AbstractPlugin { @Override public Collection> modules() { - return ImmutableList.>of(SecurityModule.class); + return ImmutableList.>of(ShieldModule.class); + } + + public static Path configDir(Environment env) { + return new File(env.configFile(), NAME).toPath(); + } + + public static Path resolveConfigFile(Environment env, String name) { + return configDir(env).resolve(name); } } diff --git a/src/main/java/org/elasticsearch/shield/support/AbstractShieldModule.java b/src/main/java/org/elasticsearch/shield/support/AbstractShieldModule.java new file mode 100644 index 00000000000..ddfd19dc597 --- /dev/null +++ b/src/main/java/org/elasticsearch/shield/support/AbstractShieldModule.java @@ -0,0 +1,72 @@ +/* + * 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.shield.support; + +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.inject.Module; +import org.elasticsearch.common.inject.SpawnModules; +import org.elasticsearch.common.settings.Settings; + +/** + * + */ +public abstract class AbstractShieldModule extends AbstractModule { + + protected final Settings settings; + protected final boolean clientMode; + + public AbstractShieldModule(Settings settings) { + this.settings = settings; + this.clientMode = !"node".equals(settings.get(Client.CLIENT_TYPE_SETTING)); + } + + @Override + protected final void configure() { + configure(clientMode); + } + + protected abstract void configure(boolean clientMode); + + public static abstract class Spawn extends AbstractShieldModule implements SpawnModules { + + protected Spawn(Settings settings) { + super(settings); + } + + @Override + public final Iterable spawnModules() { + return spawnModules(clientMode); + } + + public abstract Iterable spawnModules(boolean clientMode); + } + + public static abstract class Node extends AbstractShieldModule { + + protected Node(Settings settings) { + super(settings); + } + + @Override + protected final void configure(boolean clientMode) { + assert !clientMode : "[" + getClass().getSimpleName() + "] is a node only module"; + configureNode(); + } + + protected abstract void configureNode(); + + public static abstract class Spawn extends Node implements SpawnModules { + + protected Spawn(Settings settings) { + super(settings); + } + + public abstract Iterable spawnModules(); + } + + } +} diff --git a/src/main/java/org/elasticsearch/shield/transport/SecuredRestModule.java b/src/main/java/org/elasticsearch/shield/transport/SecuredRestModule.java index e11fffb1832..de0bc3c3632 100644 --- a/src/main/java/org/elasticsearch/shield/transport/SecuredRestModule.java +++ b/src/main/java/org/elasticsearch/shield/transport/SecuredRestModule.java @@ -5,16 +5,21 @@ */ package org.elasticsearch.shield.transport; -import org.elasticsearch.common.inject.AbstractModule; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.SecurityFilter; +import org.elasticsearch.shield.support.AbstractShieldModule; /** * */ -public class SecuredRestModule extends AbstractModule { +public class SecuredRestModule extends AbstractShieldModule.Node { + + public SecuredRestModule(Settings settings) { + super(settings); + } @Override - protected void configure() { + protected void configureNode() { bind(SecurityFilter.Rest.class).asEagerSingleton(); } } diff --git a/src/main/java/org/elasticsearch/shield/transport/SecuredTransportModule.java b/src/main/java/org/elasticsearch/shield/transport/SecuredTransportModule.java index a1a38476cfa..b68928db11e 100644 --- a/src/main/java/org/elasticsearch/shield/transport/SecuredTransportModule.java +++ b/src/main/java/org/elasticsearch/shield/transport/SecuredTransportModule.java @@ -6,12 +6,13 @@ package org.elasticsearch.shield.transport; import org.elasticsearch.common.collect.ImmutableList; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.PreProcessModule; -import org.elasticsearch.common.inject.SpawnModules; +import org.elasticsearch.common.inject.util.Providers; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.shield.SecurityFilter; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; +import org.elasticsearch.shield.support.AbstractShieldModule; import org.elasticsearch.shield.transport.n2n.IPFilteringN2NAuthenticator; import org.elasticsearch.shield.transport.netty.N2NNettyUpstreamHandler; import org.elasticsearch.shield.transport.netty.NettySecuredHttpServerTransportModule; @@ -21,28 +22,46 @@ import org.elasticsearch.transport.TransportModule; /** * */ -public class SecuredTransportModule extends AbstractModule implements SpawnModules, PreProcessModule { +public class SecuredTransportModule extends AbstractShieldModule.Spawn implements PreProcessModule { + + public SecuredTransportModule(Settings settings) { + super(settings); + } @Override - public Iterable spawnModules() { + public Iterable spawnModules(boolean clientMode) { + + if (clientMode) { + return ImmutableList.of(new NettySecuredTransportModule(settings)); + } - //todo we only need to spawn http module if we're not within the transport client context return ImmutableList.of( - new NettySecuredHttpServerTransportModule(), - new NettySecuredTransportModule()); + new NettySecuredHttpServerTransportModule(settings), + new NettySecuredTransportModule(settings)); } @Override public void processModule(Module module) { if (module instanceof TransportModule) { - ((TransportModule) module).setTransportService(SecuredTransportService.class, SecurityPlugin.NAME); + ((TransportModule) module).setTransportService(SecuredTransportService.class, ShieldPlugin.NAME); } } @Override - protected void configure() { + protected void configure(boolean clientMode) { + + if (clientMode) { + // no ip filtering on the client + bind(N2NNettyUpstreamHandler.class).toProvider(Providers.of(null)); + return; + } + bind(TransportFilter.class).to(SecurityFilter.Transport.class).asEagerSingleton(); - bind(IPFilteringN2NAuthenticator.class).asEagerSingleton(); - bind(N2NNettyUpstreamHandler.class).asEagerSingleton(); + if (settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true)) { + bind(IPFilteringN2NAuthenticator.class).asEagerSingleton(); + bind(N2NNettyUpstreamHandler.class).asEagerSingleton(); + } else { + bind(N2NNettyUpstreamHandler.class).toProvider(Providers.of(null)); + } } } diff --git a/src/main/java/org/elasticsearch/shield/transport/n2n/IPFilteringN2NAuthenticator.java b/src/main/java/org/elasticsearch/shield/transport/n2n/IPFilteringN2NAuthenticator.java index 6361e1cfc2f..7686e0e6d20 100644 --- a/src/main/java/org/elasticsearch/shield/transport/n2n/IPFilteringN2NAuthenticator.java +++ b/src/main/java/org/elasticsearch/shield/transport/n2n/IPFilteringN2NAuthenticator.java @@ -20,7 +20,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.yaml.YamlXContent; import org.elasticsearch.env.Environment; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.watcher.FileChangesListener; import org.elasticsearch.watcher.FileWatcher; import org.elasticsearch.watcher.ResourceWatcherService; @@ -60,8 +60,7 @@ public class IPFilteringN2NAuthenticator extends AbstractComponent implements N2 private Path resolveFile(Settings settings, Environment env) { String location = settings.get("ip_filter.file"); if (location == null) { - File shieldDirectory = new File(env.configFile(), SecurityPlugin.NAME); - return shieldDirectory.toPath().resolve(DEFAULT_FILE); + return ShieldPlugin.resolveConfigFile(env, DEFAULT_FILE); } return Paths.get(location); } diff --git a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransport.java b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransport.java index eaec30f11f3..0db6a2b316e 100644 --- a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransport.java +++ b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransport.java @@ -6,6 +6,7 @@ package org.elasticsearch.shield.transport.netty; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.netty.channel.ChannelPipeline; import org.elasticsearch.common.netty.channel.ChannelPipelineFactory; import org.elasticsearch.common.netty.handler.ssl.SslHandler; @@ -27,7 +28,7 @@ public class NettySecuredHttpServerTransport extends NettyHttpServerTransport { @Inject public NettySecuredHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays, - N2NNettyUpstreamHandler shieldUpstreamHandler) { + @Nullable N2NNettyUpstreamHandler shieldUpstreamHandler) { super(settings, networkService, bigArrays); this.ssl = settings.getAsBoolean("shield.http.ssl", false); this.shieldUpstreamHandler = shieldUpstreamHandler; @@ -56,7 +57,7 @@ public class NettySecuredHttpServerTransport extends NettyHttpServerTransport { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = super.getPipeline(); - if (settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true)) { + if (shieldUpstreamHandler != null) { pipeline.addFirst("ipfilter", shieldUpstreamHandler); } if (ssl) { diff --git a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransportModule.java b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransportModule.java index c3148112219..e6d1da193cc 100644 --- a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransportModule.java +++ b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredHttpServerTransportModule.java @@ -5,24 +5,30 @@ */ package org.elasticsearch.shield.transport.netty; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.PreProcessModule; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.http.HttpServerModule; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; +import org.elasticsearch.shield.support.AbstractShieldModule; /** * */ -public class NettySecuredHttpServerTransportModule extends AbstractModule implements PreProcessModule { +public class NettySecuredHttpServerTransportModule extends AbstractShieldModule implements PreProcessModule { + + public NettySecuredHttpServerTransportModule(Settings settings) { + super(settings); + } @Override public void processModule(Module module) { if (module instanceof HttpServerModule) { - ((HttpServerModule) module).setHttpServerTransport(NettySecuredHttpServerTransport.class, SecurityPlugin.NAME); + ((HttpServerModule) module).setHttpServerTransport(NettySecuredHttpServerTransport.class, ShieldPlugin.NAME); } } @Override - protected void configure() {} + protected void configure(boolean clientMode) { + } } \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransport.java b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransport.java index 4041f1ef3e0..9dace2cc907 100644 --- a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransport.java +++ b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransport.java @@ -7,6 +7,7 @@ package org.elasticsearch.shield.transport.netty; import org.elasticsearch.Version; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.inject.internal.Nullable; import org.elasticsearch.common.netty.channel.ChannelPipeline; import org.elasticsearch.common.netty.channel.ChannelPipelineFactory; import org.elasticsearch.common.netty.handler.ssl.SslHandler; @@ -29,7 +30,7 @@ public class NettySecuredTransport extends NettyTransport { @Inject public NettySecuredTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version, - N2NNettyUpstreamHandler shieldUpstreamHandler) { + @Nullable N2NNettyUpstreamHandler shieldUpstreamHandler) { super(settings, threadPool, networkService, bigArrays, version); this.shieldUpstreamHandler = shieldUpstreamHandler; this.ssl = settings.getAsBoolean("shield.transport.ssl", false); @@ -63,7 +64,7 @@ public class NettySecuredTransport extends NettyTransport { @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = super.getPipeline(); - if (settings.getAsBoolean("shield.transport.n2n.ip_filter.enabled", true)) { + if (shieldUpstreamHandler != null) { pipeline.addFirst("ipfilter", shieldUpstreamHandler); } if (ssl) { diff --git a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransportModule.java b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransportModule.java index 4d5799a476f..17071359140 100644 --- a/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransportModule.java +++ b/src/main/java/org/elasticsearch/shield/transport/netty/NettySecuredTransportModule.java @@ -5,25 +5,30 @@ */ package org.elasticsearch.shield.transport.netty; -import org.elasticsearch.common.inject.AbstractModule; import org.elasticsearch.common.inject.Module; import org.elasticsearch.common.inject.PreProcessModule; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.shield.plugin.ShieldPlugin; +import org.elasticsearch.shield.support.AbstractShieldModule; import org.elasticsearch.transport.TransportModule; /** * */ -public class NettySecuredTransportModule extends AbstractModule implements PreProcessModule { +public class NettySecuredTransportModule extends AbstractShieldModule implements PreProcessModule { + + public NettySecuredTransportModule(Settings settings) { + super(settings); + } @Override public void processModule(Module module) { if (module instanceof TransportModule) { - ((TransportModule) module).setTransport(NettySecuredTransport.class, SecurityPlugin.NAME); + ((TransportModule) module).setTransport(NettySecuredTransport.class, ShieldPlugin.NAME); } } @Override - protected void configure() {} + protected void configure(boolean clientMode) {} } \ No newline at end of file diff --git a/src/main/resources/es-plugin.properties b/src/main/resources/es-plugin.properties index 00a12dc6dac..498d3feb264 100644 --- a/src/main/resources/es-plugin.properties +++ b/src/main/resources/es-plugin.properties @@ -1,2 +1,2 @@ -plugin=org.elasticsearch.shield.plugin.SecurityPlugin +plugin=org.elasticsearch.shield.plugin.ShieldPlugin version=${project.version} diff --git a/src/test/java/org/elasticsearch/shield/audit/AuditTrailModuleTests.java b/src/test/java/org/elasticsearch/shield/audit/AuditTrailModuleTests.java index 2d8361094b0..9b5f98bec97 100644 --- a/src/test/java/org/elasticsearch/shield/audit/AuditTrailModuleTests.java +++ b/src/test/java/org/elasticsearch/shield/audit/AuditTrailModuleTests.java @@ -24,6 +24,7 @@ public class AuditTrailModuleTests extends ElasticsearchTestCase { @Test public void testEnabled() throws Exception { Settings settings = ImmutableSettings.builder() + .put("client.type", "node") .put("shield.audit.enabled", false) .build(); Injector injector = Guice.createInjector(new SettingsModule(settings), new AuditTrailModule(settings)); @@ -33,7 +34,8 @@ public class AuditTrailModuleTests extends ElasticsearchTestCase { @Test public void testDisabledByDefault() throws Exception { - Settings settings = ImmutableSettings.EMPTY; + Settings settings = ImmutableSettings.builder() + .put("client.type", "node").build(); Injector injector = Guice.createInjector(new SettingsModule(settings), new AuditTrailModule(settings)); AuditTrail auditTrail = injector.getInstance(AuditTrail.class); assertThat(auditTrail, is(AuditTrail.NOOP)); @@ -43,6 +45,7 @@ public class AuditTrailModuleTests extends ElasticsearchTestCase { public void testLogfile() throws Exception { Settings settings = ImmutableSettings.builder() .put("shield.audit.enabled", true) + .put("client.type", "node") .build(); Injector injector = Guice.createInjector(new SettingsModule(settings), new AuditTrailModule(settings)); AuditTrail auditTrail = injector.getInstance(AuditTrail.class); @@ -58,6 +61,7 @@ public class AuditTrailModuleTests extends ElasticsearchTestCase { Settings settings = ImmutableSettings.builder() .put("shield.audit.enabled", true) .put("shield.audit.outputs" , "foo") + .put("client.type", "node") .build(); try { Guice.createInjector(new SettingsModule(settings), new AuditTrailModule(settings)); diff --git a/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersModuleTests.java b/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersModuleTests.java index 048a17add55..a39a9bc6020 100644 --- a/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersModuleTests.java +++ b/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersModuleTests.java @@ -11,6 +11,7 @@ import org.elasticsearch.common.inject.Injector; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.rest.RestController; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; @@ -21,6 +22,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.mock; /** * @@ -38,7 +40,8 @@ public class ESUsersModuleTests extends ElasticsearchTestCase { @Test public void test() throws Exception { - Injector injector = Guice.createInjector(new TestModule(users, usersRoles), new ESUsersModule()); + Settings settings = ImmutableSettings.builder().put("client.type", "node").build(); + Injector injector = Guice.createInjector(new TestModule(users, usersRoles), new ESUsersModule(settings)); ESUsersRealm realm = injector.getInstance(ESUsersRealm.class); assertThat(realm, notNullValue()); assertThat(realm.userPasswdStore, notNullValue()); @@ -81,6 +84,7 @@ public class ESUsersModuleTests extends ElasticsearchTestCase { bind(Environment.class).toInstance(env); bind(ThreadPool.class).toInstance(new ThreadPool("test")); bind(ResourceWatcherService.class).asEagerSingleton(); + bind(RestController.class).toInstance(mock(RestController.class)); } } diff --git a/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java b/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java index 0e5d86f0d15..cfe32c71406 100644 --- a/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java +++ b/src/test/java/org/elasticsearch/shield/authc/esusers/ESUsersRealmTests.java @@ -13,12 +13,13 @@ import org.elasticsearch.client.AdminClient; import org.elasticsearch.client.Client; import org.elasticsearch.client.ClusterAdminClient; import org.elasticsearch.client.IndicesAdminClient; +import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestChannel; +import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestRequest; -import org.elasticsearch.shield.SecurityFilter; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.support.UserPasswdStore; import org.elasticsearch.shield.authc.support.UserRolesStore; @@ -26,25 +27,41 @@ import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.transport.TransportRequest; import org.hamcrest.Matchers; +import org.junit.Before; import org.junit.Test; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.Matchers.arrayContaining; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; /** * */ public class ESUsersRealmTests extends ElasticsearchTestCase { + private RestController restController; + private Client client; + private AdminClient adminClient; + @Before + public void init() throws Exception { + client = mock(Client.class); + adminClient = mock(AdminClient.class); + restController = mock(RestController.class); + } + + @Test + public void testRestHeaderRegistration() { + new ESUsersRealm(ImmutableSettings.EMPTY, mock(UserPasswdStore.class), mock(UserRolesStore.class), restController); + verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); + } + @Test public void testAuthenticate() throws Exception { Settings settings = ImmutableSettings.builder().build(); MockUserPasswdStore userPasswdStore = new MockUserPasswdStore("user1", "test123"); MockUserRolesStore userRolesStore = new MockUserRolesStore("user1", "role1", "role2"); - ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore); + ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore, restController); User user = realm.authenticate(new UsernamePasswordToken("user1", "test123".toCharArray())); assertTrue(userPasswdStore.called); assertTrue(userRolesStore.called); @@ -60,7 +77,7 @@ public class ESUsersRealmTests extends ElasticsearchTestCase { Settings settings = ImmutableSettings.builder().build(); MockUserPasswdStore userPasswdStore = new MockUserPasswdStore("user1", "test123"); MockUserRolesStore userRolesStore = new MockUserRolesStore("user1", "role1", "role2"); - ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore); + ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore, restController); TransportRequest request = new TransportRequest() {}; UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", "test123".toCharArray())); @@ -116,9 +133,8 @@ public class ESUsersRealmTests extends ElasticsearchTestCase { @Test @SuppressWarnings("unchecked") public void testRestHeadersAreCopied() throws Exception { // the required header will be registered only if ESUsersRealm is actually used. - new ESUsersRealm(ImmutableSettings.EMPTY, null, null); - Client client = mock(Client.class); - AdminClient adminClient = mock(AdminClient.class); + new ESUsersRealm(ImmutableSettings.EMPTY, null, null, restController); + when(restController.relevantHeaders()).thenReturn(ImmutableSet.of(UsernamePasswordToken.BASIC_AUTH_HEADER)); when(client.admin()).thenReturn(adminClient); when(adminClient.cluster()).thenReturn(mock(ClusterAdminClient.class)); when(adminClient.indices()).thenReturn(mock(IndicesAdminClient.class)); @@ -128,15 +144,16 @@ public class ESUsersRealmTests extends ElasticsearchTestCase { return null; } }; + RestRequest restRequest = mock(RestRequest.class); final Action action = mock(Action.class); final ActionListener listener = mock(ActionListener.class); - BaseRestHandler handler = new BaseRestHandler(ImmutableSettings.EMPTY, client) { + BaseRestHandler handler = new BaseRestHandler(ImmutableSettings.EMPTY, restController, client) { @Override protected void handleRequest(RestRequest restRequest, RestChannel channel, Client client) throws Exception { client.execute(action, request, listener); } }; - RestRequest restRequest = mock(RestRequest.class); + when(restRequest.header(UsernamePasswordToken.BASIC_AUTH_HEADER)).thenReturn("foobar"); RestChannel channel = mock(RestChannel.class); handler.handleRequest(restRequest, channel); diff --git a/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTest.java b/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTest.java index 5d2104cdbc9..58171561639 100644 --- a/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTest.java +++ b/src/test/java/org/elasticsearch/shield/authc/ldap/LdapRealmTest.java @@ -8,11 +8,13 @@ package org.elasticsearch.shield.authc.ldap; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.rest.RestController; import org.elasticsearch.shield.User; import org.elasticsearch.shield.authc.support.UsernamePasswordToken; import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.watcher.ResourceWatcherService; +import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -31,9 +33,22 @@ public class LdapRealmTest extends ElasticsearchTestCase { public static final String VALID_USERNAME = "Thomas Masterman Hardy"; public static final String PASSWORD = "pass"; + private RestController restController; + + @Before + public void init() throws Exception { + restController = mock(RestController.class); + } + @Rule public static ApacheDsRule apacheDsRule = new ApacheDsRule(); + @Test + public void testRestHeaderRegistration() { + new LdapRealm(ImmutableSettings.EMPTY, mock(LdapConnectionFactory.class), mock(LdapGroupToRoleMapper.class), restController); + verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER); + } + @Test public void testAuthenticate_subTreeGroupSearch(){ String groupSearchBase = "o=sevenSeas"; @@ -41,7 +56,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { String userTemplate = VALID_USER_TEMPLATE; Settings settings = LdapConnectionTests.buildLdapSettings(apacheDsRule.getUrl(), userTemplate, groupSearchBase, isSubTreeSearch); StandardLdapConnectionFactory ldapFactory = new StandardLdapConnectionFactory(settings); - LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); assertThat( user, notNullValue()); @@ -56,7 +71,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { StandardLdapConnectionFactory ldapFactory = new StandardLdapConnectionFactory( LdapConnectionTests.buildLdapSettings(apacheDsRule.getUrl(), userTemplate, groupSearchBase, isSubTreeSearch)); - LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); assertThat( user, notNullValue()); @@ -73,7 +88,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { LdapConnectionTests.buildLdapSettings( apacheDsRule.getUrl(), userTemplate, groupSearchBase, isSubTreeSearch) ); ldapFactory = spy(ldapFactory); - LdapRealm ldap = new LdapRealm( buildCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm( buildCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); @@ -90,7 +105,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { LdapConnectionTests.buildLdapSettings(apacheDsRule.getUrl(), userTemplate, groupSearchBase, isSubTreeSearch) ); ldapFactory = spy(ldapFactory); - LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, PASSWORD.toCharArray())); @@ -107,7 +122,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { ActiveDirectoryConnectionFactory ldapFactory = new ActiveDirectoryConnectionFactory( ActiveDirectoryFactoryTests.buildAdSettings(AD_URL, adDomain)); - LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate( new UsernamePasswordToken("george", "R))Tr0x".toCharArray())); @@ -125,7 +140,7 @@ public class LdapRealmTest extends ElasticsearchTestCase { .build(); ActiveDirectoryConnectionFactory ldapFactory = new ActiveDirectoryConnectionFactory( settings ); - LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper()); + LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(), restController); User user = ldap.authenticate( new UsernamePasswordToken("george", "R))Tr0x".toCharArray())); assertThat( user, notNullValue()); diff --git a/src/test/java/org/elasticsearch/shield/plugin/ShieldPluginTests.java b/src/test/java/org/elasticsearch/shield/plugin/ShieldPluginTests.java index c611937288f..17d632c1a4c 100644 --- a/src/test/java/org/elasticsearch/shield/plugin/ShieldPluginTests.java +++ b/src/test/java/org/elasticsearch/shield/plugin/ShieldPluginTests.java @@ -22,7 +22,7 @@ public class ShieldPluginTests extends ShieldIntegrationTest { logger.info("--> Checking nodes info that shield plugin is loaded"); for (NodeInfo nodeInfo : nodeInfos.getNodes()) { assertThat(nodeInfo.getPlugins().getInfos(), hasSize(1)); - assertThat(nodeInfo.getPlugins().getInfos().get(0).getName(), is(SecurityPlugin.NAME)); + assertThat(nodeInfo.getPlugins().getInfos().get(0).getName(), is(ShieldPlugin.NAME)); } } diff --git a/src/test/java/org/elasticsearch/shield/test/ShieldAssertions.java b/src/test/java/org/elasticsearch/shield/test/ShieldAssertions.java index 7d4b34b9bb8..f56c5c7bc9d 100644 --- a/src/test/java/org/elasticsearch/shield/test/ShieldAssertions.java +++ b/src/test/java/org/elasticsearch/shield/test/ShieldAssertions.java @@ -6,17 +6,17 @@ package org.elasticsearch.shield.test; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.shield.SecurityException; +import org.elasticsearch.shield.ShieldException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; public class ShieldAssertions { - public static void assertContainsWWWAuthenticateHeader(org.elasticsearch.shield.SecurityException e) { + public static void assertContainsWWWAuthenticateHeader(ShieldException e) { assertThat(e.status(), is(RestStatus.UNAUTHORIZED)); assertThat(e.getHeaders(), hasKey("WWW-Authenticate")); assertThat(e.getHeaders().get("WWW-Authenticate"), hasSize(1)); - assertThat(e.getHeaders().get("WWW-Authenticate").get(0), is(SecurityException.HEADERS.get("WWW-Authenticate").get(0))); + assertThat(e.getHeaders().get("WWW-Authenticate").get(0), is(ShieldException.HEADERS.get("WWW-Authenticate").get(0))); } } diff --git a/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java b/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java index 4934cdcdd55..b93be37a4f9 100644 --- a/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java +++ b/src/test/java/org/elasticsearch/shield/test/ShieldIntegrationTest.java @@ -15,7 +15,7 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.plugins.PluginsService; -import org.elasticsearch.shield.plugin.SecurityPlugin; +import org.elasticsearch.shield.plugin.ShieldPlugin; import org.elasticsearch.shield.transport.netty.NettySecuredTransport; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.transport.Transport; @@ -65,7 +65,7 @@ public abstract class ShieldIntegrationTest extends ElasticsearchIntegrationTest .put("discovery.zen.ping.multicast.enabled", false) .put("discovery.type", "zen") .put("node.mode", "network") - .put("plugin.types", SecurityPlugin.class.getName()) + .put("plugin.types", ShieldPlugin.class.getName()) .put("shield.authc.esusers.files.users", writeFile(folder, "users", CONFIG_STANDARD_USER)) .put("shield.authc.esusers.files.users_roles", writeFile(folder, "users_roles", CONFIG_STANDARD_USER_ROLES)) .put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", CONFIG_ROLE_ALLOW_ALL)) diff --git a/src/test/resources/org/elasticsearch/shield/authz/actions b/src/test/resources/org/elasticsearch/shield/authz/actions index 77307b73da7..cffc0c38315 100644 --- a/src/test/resources/org/elasticsearch/shield/authz/actions +++ b/src/test/resources/org/elasticsearch/shield/authz/actions @@ -25,6 +25,7 @@ indices:admin/cache/clear indices:admin/close indices:admin/create indices:admin/delete +indices:admin/get indices:admin/exists indices:admin/flush indices:admin/mapping/delete