Cleanup
- Formalized the notion of a client vs. node mode. Introduced an `AbstractShieldModule` that takes care of that - For now, standarized on the `Shield` name across the board (e.g. change `SecurityModule` to `ShieldModule`) - Introduces static methods to `ShieldPlugin` to resolve shield specific config files (on the way fixed the file resolving of the ldap group mapper) - The n2n ip filtering is now resolved at the module level. If not enabled, null is injected and the netty handler is then not injected to the pipeline - updated code base with the latest changes in es-core around how relevant http headers are registered and copied over to the transport request - Added new known action in es-core `indices:admin/get` Original commit: elastic/x-pack-elasticsearch@ca8d85dc81
This commit is contained in:
parent
787a415c27
commit
1588c761ea
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String, List<String>> HEADERS = ImmutableMap.<String, List<String>>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);
|
||||
}
|
||||
}
|
|
@ -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<? extends Module> spawnModules() {
|
||||
public Iterable<? extends Module> 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) {
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<? extends Module> spawnModules() {
|
||||
ImmutableList.Builder<Module> 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<? extends Node> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.<ESUsersRealm>of(null));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean enabled(Settings settings) {
|
||||
return settings.getComponentSettings(ESUsersModule.class).getAsBoolean("enabled", true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<UsernamePasswordToken> {
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<LdapName, Set<String>> 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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<UsernamePasswordToken> {
|
||||
|
||||
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 Realm<Use
|
|||
User.Simple user = new User.Simple(token.principal(), roles.toArray(new String[roles.size()]));
|
||||
Arrays.fill(token.credentials(), '\0');
|
||||
return user;
|
||||
} catch (SecurityException e){
|
||||
} catch (ShieldException e){
|
||||
logger.info("Authentication Failed for user [{}]", e, token.principal());
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -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.NamingException;
|
||||
|
@ -43,11 +44,11 @@ public class StandardLdapConnectionFactory extends AbstractComponent implements
|
|||
super(settings);
|
||||
userDnTemplates = componentSettings.getAsArray(USER_DN_TEMPLATES_SETTING);
|
||||
if (userDnTemplates == null) {
|
||||
throw new org.elasticsearch.shield.SecurityException("Missing required ldap setting [" + USER_DN_TEMPLATES_SETTING + "]");
|
||||
throw new ShieldException("Missing required ldap setting [" + USER_DN_TEMPLATES_SETTING + "]");
|
||||
}
|
||||
String[] ldapUrls = componentSettings.getAsArray(URLS_SETTING);
|
||||
if (ldapUrls == null) {
|
||||
throw new org.elasticsearch.shield.SecurityException("Missing required ldap setting [" + URLS_SETTING + "]");
|
||||
throw new ShieldException("Missing required ldap setting [" + URLS_SETTING + "]");
|
||||
}
|
||||
sharedLdapEnv = ImmutableMap.<String, Serializable>builder()
|
||||
.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory")
|
||||
|
|
|
@ -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<AuthenticationToken> {
|
|||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Class<? extends Module>> modules() {
|
||||
return ImmutableList.<Class<? extends Module>>of(SecurityModule.class);
|
||||
return ImmutableList.<Class<? extends Module>>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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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<? extends Module> spawnModules() {
|
||||
return spawnModules(clientMode);
|
||||
}
|
||||
|
||||
public abstract Iterable<? extends Module> 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<? extends AbstractShieldModule.Node> spawnModules();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<? extends Module> spawnModules() {
|
||||
public Iterable<? extends Module> 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.<N2NNettyUpstreamHandler>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.<N2NNettyUpstreamHandler>of(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
plugin=org.elasticsearch.shield.plugin.SecurityPlugin
|
||||
plugin=org.elasticsearch.shield.plugin.ShieldPlugin
|
||||
version=${project.version}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue