mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-08 05:58:44 +00:00
Introduced realms factories
Today it is possible to configure 3 realms in shield - `esusers`, `ldap` and `active_directory`. These realms are created once based on the configuration. There are several problems with this approach: - Taking `ldap` as an example, it is currently not possible to have multiple `ldap` realms configured (where one serving as a fallback for the other). While the `ldap` realm itself enables defining multiple ldap URLs, it has the limitation that the fallback LDAP must have the exact same configuration as the primary LDAP (+ there's the limitation that all URLs must either us SSL or not... there cannot be a mix of SSL URL and a normal URL) - The realms are created and bound internally by guice. This will limit the configurability at runtime of the realms which we might want to introduce in shield 2.0. This commit changes the way realms are managed & configured. Instead of having guice bind the realms themselves. A new realm factory construct will be introduced. The realm factory will represent a realm type and guice will bind these factories. At load time, we'll read the configuration and based on the types of the configured realms, the relevant factories will create the realms based on the settings. This means that potentially we can expose the realms as a dynamic configuration and rebuild the realm chain at runtime. A nice side effect of this approach is that the multiple URLs feature that is currently supported by both `ldap` and `active_directory` can be dropped. Instead, the users will just need to configure multiple `ldap`/`active_directory` realms. Closes: elastic/elasticsearch#370 Original commit: elastic/x-pack-elasticsearch@3232f153bb
This commit is contained in:
parent
f178575625
commit
af74f43aea
@ -63,3 +63,6 @@ java.nio.channels.ReadableByteChannel#read(java.nio.ByteBuffer)
|
|||||||
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[])
|
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[])
|
||||||
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[], int, int)
|
java.nio.channels.ScatteringByteChannel#read(java.nio.ByteBuffer[], int, int)
|
||||||
java.nio.channels.FileChannel#read(java.nio.ByteBuffer, long)
|
java.nio.channels.FileChannel#read(java.nio.ByteBuffer, long)
|
||||||
|
|
||||||
|
@defaultMessage The LdapSslSocketFactory should never be cleared manually as it may lead to threading issues.
|
||||||
|
org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory#clear()
|
@ -5,32 +5,36 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc;
|
package org.elasticsearch.shield.authc;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.ImmutableList;
|
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.authc.active_directory.ActiveDirectoryModule;
|
import org.elasticsearch.shield.authc.active_directory.ActiveDirectoryRealm;
|
||||||
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.support.ldap.LdapSslSocketFactory;
|
||||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class AuthenticationModule extends AbstractShieldModule.Node.Spawn {
|
public class AuthenticationModule extends AbstractShieldModule.Node {
|
||||||
|
|
||||||
public AuthenticationModule(Settings settings) {
|
public AuthenticationModule(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterable<? extends Node> spawnModules() {
|
|
||||||
return ImmutableList.of(
|
|
||||||
new ESUsersModule(settings),
|
|
||||||
new LdapModule(settings),
|
|
||||||
new ActiveDirectoryModule(settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configureNode() {
|
protected void configureNode() {
|
||||||
|
|
||||||
|
// This socket factory needs to be configured before any LDAP connections are created. LDAP configuration
|
||||||
|
// for JNDI invokes a static getSocketFactory method from LdapSslSocketFactory.
|
||||||
|
requestStaticInjection(LdapSslSocketFactory.class);
|
||||||
|
|
||||||
|
MapBinder<String, Realm.Factory> mapBinder = MapBinder.newMapBinder(binder(), String.class, Realm.Factory.class);
|
||||||
|
mapBinder.addBinding(ESUsersRealm.TYPE).to(ESUsersRealm.Factory.class).asEagerSingleton();
|
||||||
|
mapBinder.addBinding(ActiveDirectoryRealm.TYPE).to(ActiveDirectoryRealm.Factory.class).asEagerSingleton();
|
||||||
|
mapBinder.addBinding(LdapRealm.TYPE).to(LdapRealm.Factory.class).asEagerSingleton();
|
||||||
|
|
||||||
|
bind(Realms.class).asEagerSingleton();
|
||||||
bind(AuthenticationService.class).to(InternalAuthenticationService.class).asEagerSingleton();
|
bind(AuthenticationService.class).to(InternalAuthenticationService.class).asEagerSingleton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
|
|||||||
static final String TOKEN_KEY = "_shield_token";
|
static final String TOKEN_KEY = "_shield_token";
|
||||||
static final String USER_KEY = "_shield_user";
|
static final String USER_KEY = "_shield_user";
|
||||||
|
|
||||||
private final Realm[] realms;
|
private final Realms realms;
|
||||||
private final AuditTrail auditTrail;
|
private final AuditTrail auditTrail;
|
||||||
private final SignatureService signatureService;
|
private final SignatureService signatureService;
|
||||||
private final boolean signUserHeader;
|
private final boolean signUserHeader;
|
||||||
@ -38,7 +38,7 @@ public class InternalAuthenticationService extends AbstractComponent implements
|
|||||||
@Inject
|
@Inject
|
||||||
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, SignatureService signatureService) {
|
public InternalAuthenticationService(Settings settings, Realms realms, AuditTrail auditTrail, SignatureService signatureService) {
|
||||||
super(settings);
|
super(settings);
|
||||||
this.realms = realms.realms();
|
this.realms = realms;
|
||||||
this.auditTrail = auditTrail;
|
this.auditTrail = auditTrail;
|
||||||
this.signatureService = signatureService;
|
this.signatureService = signatureService;
|
||||||
this.signUserHeader = componentSettings.getAsBoolean("sign_user_header", true);
|
this.signUserHeader = componentSettings.getAsBoolean("sign_user_header", true);
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc;
|
package org.elasticsearch.shield.authc;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
import org.elasticsearch.transport.TransportMessage;
|
import org.elasticsearch.transport.TransportMessage;
|
||||||
@ -14,17 +17,52 @@ import org.elasticsearch.transport.TransportMessage;
|
|||||||
* delegates the authentication process. Different realms may be defined, each may be based on different
|
* delegates the authentication process. Different realms may be defined, each may be based on different
|
||||||
* authentication mechanism supporting its own specific authentication token type.
|
* authentication mechanism supporting its own specific authentication token type.
|
||||||
*/
|
*/
|
||||||
public interface Realm<T extends AuthenticationToken> {
|
public abstract class Realm<T extends AuthenticationToken> implements Comparable<Realm> {
|
||||||
|
|
||||||
|
protected final ESLogger logger = Loggers.getLogger(getClass());
|
||||||
|
|
||||||
|
protected final String type;
|
||||||
|
protected final String name;
|
||||||
|
protected final Settings settings;
|
||||||
|
protected final int order;
|
||||||
|
|
||||||
|
public Realm(String type, String name, Settings settings) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
this.settings = settings;
|
||||||
|
this.order = settings.getAsInt("order", Integer.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The type of this realm
|
* @return The type of this realm
|
||||||
*/
|
*/
|
||||||
String type();
|
public String type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The name of this realm.
|
||||||
|
*/
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The order of this realm within the executing realm chain.
|
||||||
|
*/
|
||||||
|
public int order() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Realm other) {
|
||||||
|
return Integer.compare(order, other.order);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@code true} if this realm supports the given authentication token, {@code false} otherwise.
|
* @return {@code true} if this realm supports the given authentication token, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
boolean supports(AuthenticationToken token);
|
public abstract boolean supports(AuthenticationToken token);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to extract an authentication token from the given rest request. If an appropriate token
|
* Attempts to extract an authentication token from the given rest request. If an appropriate token
|
||||||
@ -33,7 +71,7 @@ public interface Realm<T extends AuthenticationToken> {
|
|||||||
* @param request The rest request
|
* @param request The rest request
|
||||||
* @return The authentication token or {@code null} if not found
|
* @return The authentication token or {@code null} if not found
|
||||||
*/
|
*/
|
||||||
T token(RestRequest request);
|
public abstract T token(RestRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to extract an authentication token from the given transport message. If an appropriate token
|
* Attempts to extract an authentication token from the given transport message. If an appropriate token
|
||||||
@ -42,7 +80,7 @@ public interface Realm<T extends AuthenticationToken> {
|
|||||||
* @param message The transport message
|
* @param message The transport message
|
||||||
* @return The authentication token or {@code null} if not found
|
* @return The authentication token or {@code null} if not found
|
||||||
*/
|
*/
|
||||||
T token(TransportMessage<?> message);
|
public abstract T token(TransportMessage<?> message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates the given token. A successful authentication will return the User associated
|
* Authenticates the given token. A successful authentication will return the User associated
|
||||||
@ -51,6 +89,47 @@ public interface Realm<T extends AuthenticationToken> {
|
|||||||
* @param token The authentication token
|
* @param token The authentication token
|
||||||
* @return The authenticated user or {@code null} if authentication failed.
|
* @return The authenticated user or {@code null} if authentication failed.
|
||||||
*/
|
*/
|
||||||
User authenticate(T token);
|
public abstract User authenticate(T token);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A factory for a specific realm type. Knows how to create a new realm given the appropriate
|
||||||
|
* settings
|
||||||
|
*/
|
||||||
|
public static abstract class Factory<R extends Realm> {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final boolean internal;
|
||||||
|
|
||||||
|
public Factory(String type, boolean internal) {
|
||||||
|
this.type = type;
|
||||||
|
this.internal = internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The type of the ream this factory creates
|
||||||
|
*/
|
||||||
|
public String type() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean internal() {
|
||||||
|
return internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new realm based on the given settigns.
|
||||||
|
*
|
||||||
|
* @param settings The settings for the realm.
|
||||||
|
* @return The new realm (this method never returns {@code null}).
|
||||||
|
*/
|
||||||
|
public abstract R create(String name, Settings settings);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a default realm, one that has no custom settings. Some realms might require minimal
|
||||||
|
* settings, in which case, this method will return {@code null}.
|
||||||
|
*/
|
||||||
|
public abstract R createDefault(String name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,46 +5,105 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc;
|
package org.elasticsearch.shield.authc;
|
||||||
|
|
||||||
|
import org.apache.lucene.util.CollectionUtil;
|
||||||
|
import org.elasticsearch.common.collect.Lists;
|
||||||
|
import org.elasticsearch.common.collect.Sets;
|
||||||
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.logging.ESLoggerFactory;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
import org.elasticsearch.shield.authc.active_directory.ActiveDirectoryRealm;
|
|
||||||
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
||||||
import org.elasticsearch.shield.authc.ldap.LdapRealm;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serves as a realms registry (also responsible for ordering the realms appropriately)
|
* Serves as a realms registry (also responsible for ordering the realms appropriately)
|
||||||
*/
|
*/
|
||||||
public class Realms {
|
public class Realms extends AbstractComponent implements Iterable<Realm> {
|
||||||
|
|
||||||
private static final ESLogger logger = ESLoggerFactory.getLogger(Realms.class.getName());
|
private final Map<String, Realm.Factory> factories;
|
||||||
|
|
||||||
private final Realm[] realms;
|
private final List<Realm> realms;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Realms(@Nullable ESUsersRealm esusers, @Nullable LdapRealm ldap, @Nullable ActiveDirectoryRealm activeDirectory) {
|
public Realms(Settings settings, Map<String, Realm.Factory> factories) {
|
||||||
|
super(settings);
|
||||||
List<Realm> realms = new ArrayList<>();
|
this.factories = factories;
|
||||||
if (esusers != null) {
|
realms = new CopyOnWriteArrayList<>(initRealms());
|
||||||
logger.info("Realm [" + esusers.type() + "] is used");
|
|
||||||
realms.add(esusers);
|
|
||||||
}
|
|
||||||
if (ldap != null) {
|
|
||||||
logger.info("Realm [" + ldap.type() + "] is used");
|
|
||||||
realms.add(ldap);
|
|
||||||
}
|
|
||||||
if (activeDirectory != null) {
|
|
||||||
logger.info("Realm [" + activeDirectory.type() + "] is used");
|
|
||||||
realms.add(activeDirectory);
|
|
||||||
}
|
|
||||||
this.realms = realms.toArray(new Realm[realms.size()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Realm[] realms() {
|
@Override
|
||||||
|
public Iterator<Realm> iterator() {
|
||||||
|
return realms.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Realm.Factory realmFactory(String type) {
|
||||||
|
return factories.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Realm> initRealms() {
|
||||||
|
Settings realmsSettings = componentSettings.getAsSettings("realms");
|
||||||
|
Set<String> internalTypes = Sets.newHashSet();
|
||||||
|
List<Realm> realms = Lists.newArrayList();
|
||||||
|
for (String name : realmsSettings.names()) {
|
||||||
|
Settings realmSettings = realmsSettings.getAsSettings(name);
|
||||||
|
String type = realmSettings.get("type");
|
||||||
|
if (type == null) {
|
||||||
|
throw new ShieldSettingsException("Missing realm type for in [" + name + "] realm");
|
||||||
|
}
|
||||||
|
Realm.Factory factory = factories.get(type);
|
||||||
|
if (factory == null) {
|
||||||
|
throw new ShieldSettingsException("Unknown reaml type [" + type + "] set for realm [" + name + "]");
|
||||||
|
}
|
||||||
|
if (factory.internal()) {
|
||||||
|
// this is an internal realm factory, let's make sure we didn't already registered one
|
||||||
|
// (there can only be one instance of an internal realm)
|
||||||
|
if (internalTypes.contains(type)) {
|
||||||
|
throw new ShieldSettingsException("Multiple [" + type + "] realms are configured. [" + type +
|
||||||
|
"] is an internal realm and therefore there can only be one such realm configured");
|
||||||
|
}
|
||||||
|
internalTypes.add(type);
|
||||||
|
}
|
||||||
|
realms.add(factory.create(name, realmSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!realms.isEmpty()) {
|
||||||
|
CollectionUtil.introSort(realms);
|
||||||
|
return realms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// there is no "realms" configuration, go over all the factories and try to create defaults
|
||||||
|
// for all the internal realms
|
||||||
|
realms.add(factories.get(ESUsersRealm.TYPE).createDefault("default_" + ESUsersRealm.TYPE));
|
||||||
return realms;
|
return realms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the settings for the internal realm of the given type. Typically, internal realms may or may
|
||||||
|
* not be configured. If they are not configured, they work OOTB using default settings. If they are
|
||||||
|
* configured, there can only be one configure for an internal realm.
|
||||||
|
*/
|
||||||
|
public static Settings internalRealmSettings(Settings settings, String realmType) {
|
||||||
|
Settings realmsSettings = settings.getComponentSettings(Realms.class).getAsSettings("realms");
|
||||||
|
Settings result = null;
|
||||||
|
for (String name : realmsSettings.names()) {
|
||||||
|
Settings realmSettings = realmsSettings.getAsSettings(name);
|
||||||
|
String type = realmSettings.get("type");
|
||||||
|
if (type == null) {
|
||||||
|
throw new ShieldSettingsException("Missing realm type for in [" + name + "] realm");
|
||||||
|
}
|
||||||
|
if (type.equals(realmType)) {
|
||||||
|
if (result != null) {
|
||||||
|
throw new ShieldSettingsException("Multiple [" + realmType + "] are configured. Only one [" + realmType + "] may be configured");
|
||||||
|
}
|
||||||
|
result = realmSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result != null ? result : ImmutableSettings.EMPTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ package org.elasticsearch.shield.authc.active_directory;
|
|||||||
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.ShieldSettingsException;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
@ -31,7 +30,7 @@ import java.util.Hashtable;
|
|||||||
* user entry in Active Directory that matches the user name). This eliminates the need for user templates, and simplifies
|
* user entry in Active Directory that matches the user name). This eliminates the need for user templates, and simplifies
|
||||||
* the configuration for windows admins that may not be familiar with LDAP concepts.
|
* the configuration for windows admins that may not be familiar with LDAP concepts.
|
||||||
*/
|
*/
|
||||||
public class ActiveDirectoryConnectionFactory extends AbstractComponent implements ConnectionFactory {
|
public class ActiveDirectoryConnectionFactory extends ConnectionFactory {
|
||||||
|
|
||||||
public static final String AD_DOMAIN_NAME_SETTING = "domain_name";
|
public static final String AD_DOMAIN_NAME_SETTING = "domain_name";
|
||||||
public static final String AD_USER_SEARCH_BASEDN_SETTING = "user_search_dn";
|
public static final String AD_USER_SEARCH_BASEDN_SETTING = "user_search_dn";
|
||||||
@ -43,13 +42,13 @@ public class ActiveDirectoryConnectionFactory extends AbstractComponent implemen
|
|||||||
@Inject
|
@Inject
|
||||||
public ActiveDirectoryConnectionFactory(Settings settings) {
|
public ActiveDirectoryConnectionFactory(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
domainName = componentSettings.get(AD_DOMAIN_NAME_SETTING);
|
domainName = settings.get(AD_DOMAIN_NAME_SETTING);
|
||||||
if (domainName == null) {
|
if (domainName == null) {
|
||||||
throw new ShieldSettingsException("Missing [" + AD_DOMAIN_NAME_SETTING + "] setting for active directory");
|
throw new ShieldSettingsException("Missing [" + AD_DOMAIN_NAME_SETTING + "] setting for active directory");
|
||||||
}
|
}
|
||||||
userSearchDN = componentSettings.get(AD_USER_SEARCH_BASEDN_SETTING, buildDnFromDomain(domainName));
|
userSearchDN = settings.get(AD_USER_SEARCH_BASEDN_SETTING, buildDnFromDomain(domainName));
|
||||||
|
|
||||||
String[] ldapUrls = componentSettings.getAsArray(URLS_SETTING, new String[] { "ldaps://" + domainName + ":636" });
|
String[] ldapUrls = settings.getAsArray(URLS_SETTING, new String[] { "ldaps://" + domainName + ":636" });
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder()
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder()
|
||||||
.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory")
|
.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory")
|
||||||
|
@ -18,6 +18,6 @@ public class ActiveDirectoryGroupToRoleMapper extends AbstractGroupToRoleMapper
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ActiveDirectoryGroupToRoleMapper(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
public ActiveDirectoryGroupToRoleMapper(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
||||||
super(settings, ActiveDirectoryRealm.type, env, watcherService, null);
|
super(settings, ActiveDirectoryRealm.TYPE, env, watcherService, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.active_directory;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
|
||||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures ActiveDirectory Realm object injections
|
|
||||||
*/
|
|
||||||
public class ActiveDirectoryModule extends AbstractShieldModule.Node {
|
|
||||||
|
|
||||||
private final boolean enabled;
|
|
||||||
|
|
||||||
public ActiveDirectoryModule(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
enabled = enabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configureNode() {
|
|
||||||
if (enabled) {
|
|
||||||
/* This socket factory needs to be configured before any LDAP connections are created. LDAP configuration
|
|
||||||
for JNDI invokes a static getSocketFactory method from LdapSslSocketFactory. */
|
|
||||||
requestStaticInjection(LdapSslSocketFactory.class);
|
|
||||||
|
|
||||||
bind(ActiveDirectoryRealm.class).asEagerSingleton();
|
|
||||||
} else {
|
|
||||||
bind(ActiveDirectoryRealm.class).toProvider(Providers.<ActiveDirectoryRealm>of(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean enabled(Settings settings) {
|
|
||||||
Settings authcSettings = settings.getAsSettings("shield.authc");
|
|
||||||
if (!authcSettings.names().contains(ActiveDirectoryRealm.type)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Settings adSettings = authcSettings.getAsSettings(ActiveDirectoryRealm.type);
|
|
||||||
return adSettings.getAsBoolean("enabled", true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,26 +7,48 @@ package org.elasticsearch.shield.authc.active_directory;
|
|||||||
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapRealm;
|
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapRealm;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ActiveDirectoryRealm extends AbstractLdapRealm {
|
public class ActiveDirectoryRealm extends AbstractLdapRealm {
|
||||||
|
|
||||||
public static final String type = "active_directory";
|
public static final String TYPE = "active_directory";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ActiveDirectoryRealm(Settings settings,
|
public ActiveDirectoryRealm(String name, Settings settings, ActiveDirectoryConnectionFactory connectionFactory,
|
||||||
ActiveDirectoryConnectionFactory connectionFactory,
|
ActiveDirectoryGroupToRoleMapper roleMapper) {
|
||||||
ActiveDirectoryGroupToRoleMapper roleMapper,
|
|
||||||
RestController restController) {
|
super(name, TYPE, settings, connectionFactory, roleMapper);
|
||||||
super(settings, connectionFactory, roleMapper, restController);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return type;
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class Factory extends AbstractLdapRealm.Factory<ActiveDirectoryRealm> {
|
||||||
|
|
||||||
|
private final Environment env;
|
||||||
|
private final ResourceWatcherService watcherService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Factory(Environment env, ResourceWatcherService watcherService, RestController restController) {
|
||||||
|
super(ActiveDirectoryRealm.TYPE, restController);
|
||||||
|
this.env = env;
|
||||||
|
this.watcherService = watcherService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActiveDirectoryRealm create(String name, Settings settings) {
|
||||||
|
ActiveDirectoryConnectionFactory connectionFactory = new ActiveDirectoryConnectionFactory(settings);
|
||||||
|
ActiveDirectoryGroupToRoleMapper roleMapper = new ActiveDirectoryGroupToRoleMapper(settings, env, watcherService);
|
||||||
|
return new ActiveDirectoryRealm(name, settings, connectionFactory, roleMapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.esusers;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ESUsersModule extends AbstractShieldModule.Node {
|
|
||||||
|
|
||||||
private final boolean enabled;
|
|
||||||
|
|
||||||
public ESUsersModule(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
enabled = enabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configureNode() {
|
|
||||||
if (enabled) {
|
|
||||||
bind(ESUsersRealm.class).asEagerSingleton();
|
|
||||||
bind(FileUserPasswdStore.class).asEagerSingleton();
|
|
||||||
bind(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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,15 +6,19 @@
|
|||||||
package org.elasticsearch.shield.authc.esusers;
|
package org.elasticsearch.shield.authc.esusers;
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
import org.elasticsearch.rest.RestRequest;
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||||
|
import org.elasticsearch.shield.authc.Realm;
|
||||||
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
|
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
|
||||||
import org.elasticsearch.shield.authc.support.RefreshListener;
|
import org.elasticsearch.shield.authc.support.RefreshListener;
|
||||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||||
import org.elasticsearch.transport.TransportMessage;
|
import org.elasticsearch.transport.TransportMessage;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -26,16 +30,13 @@ public class ESUsersRealm extends CachingUsernamePasswordRealm {
|
|||||||
final FileUserPasswdStore userPasswdStore;
|
final FileUserPasswdStore userPasswdStore;
|
||||||
final FileUserRolesStore userRolesStore;
|
final FileUserRolesStore userRolesStore;
|
||||||
|
|
||||||
@Inject
|
public ESUsersRealm(String name, Settings settings, FileUserPasswdStore userPasswdStore, FileUserRolesStore userRolesStore) {
|
||||||
public ESUsersRealm(Settings settings, FileUserPasswdStore userPasswdStore,
|
super(name, TYPE, settings);
|
||||||
FileUserRolesStore userRolesStore, RestController restController) {
|
|
||||||
super(settings);
|
|
||||||
Listener listener = new Listener();
|
Listener listener = new Listener();
|
||||||
this.userPasswdStore = userPasswdStore;
|
this.userPasswdStore = userPasswdStore;
|
||||||
userPasswdStore.addListener(listener);
|
userPasswdStore.addListener(listener);
|
||||||
this.userRolesStore = userRolesStore;
|
this.userRolesStore = userRolesStore;
|
||||||
userRolesStore.addListener(listener);
|
userRolesStore.addListener(listener);
|
||||||
restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -73,4 +74,30 @@ public class ESUsersRealm extends CachingUsernamePasswordRealm {
|
|||||||
expireAll();
|
expireAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Factory extends Realm.Factory<ESUsersRealm> {
|
||||||
|
|
||||||
|
private final Environment env;
|
||||||
|
private final ResourceWatcherService watcherService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Factory(Environment env, ResourceWatcherService watcherService, RestController restController) {
|
||||||
|
super(TYPE, true);
|
||||||
|
this.env = env;
|
||||||
|
this.watcherService = watcherService;
|
||||||
|
restController.registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESUsersRealm create(String name, Settings settings) {
|
||||||
|
FileUserPasswdStore userPasswdStore = new FileUserPasswdStore(settings, env, watcherService);
|
||||||
|
FileUserRolesStore userRolesStore = new FileUserRolesStore(settings, env, watcherService);
|
||||||
|
return new ESUsersRealm(name, settings, userPasswdStore, userRolesStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ESUsersRealm createDefault(String name) {
|
||||||
|
return create(name, ImmutableSettings.EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,15 @@ package org.elasticsearch.shield.authc.esusers;
|
|||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.base.Charsets;
|
import org.elasticsearch.common.base.Charsets;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.inject.internal.Nullable;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.shield.ShieldPlugin;
|
||||||
import org.elasticsearch.shield.authc.support.Hasher;
|
import org.elasticsearch.shield.authc.support.Hasher;
|
||||||
import org.elasticsearch.shield.authc.support.RefreshListener;
|
import org.elasticsearch.shield.authc.support.RefreshListener;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||||
import org.elasticsearch.shield.ShieldPlugin;
|
|
||||||
import org.elasticsearch.watcher.FileChangesListener;
|
import org.elasticsearch.watcher.FileChangesListener;
|
||||||
import org.elasticsearch.watcher.FileWatcher;
|
import org.elasticsearch.watcher.FileWatcher;
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
@ -37,7 +36,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class FileUserPasswdStore extends AbstractComponent {
|
public class FileUserPasswdStore {
|
||||||
|
|
||||||
|
private static final ESLogger logger = Loggers.getLogger(FileUserPasswdStore.class);
|
||||||
|
|
||||||
private final Path file;
|
private final Path file;
|
||||||
final Hasher hasher = Hasher.HTPASSWD;
|
final Hasher hasher = Hasher.HTPASSWD;
|
||||||
@ -46,13 +47,11 @@ public class FileUserPasswdStore extends AbstractComponent {
|
|||||||
|
|
||||||
private CopyOnWriteArrayList<RefreshListener> listeners;
|
private CopyOnWriteArrayList<RefreshListener> listeners;
|
||||||
|
|
||||||
@Inject
|
|
||||||
public FileUserPasswdStore(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
public FileUserPasswdStore(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
||||||
this(settings, env, watcherService, null);
|
this(settings, env, watcherService, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUserPasswdStore(Settings settings, Environment env, ResourceWatcherService watcherService, RefreshListener listener) {
|
FileUserPasswdStore(Settings settings, Environment env, ResourceWatcherService watcherService, RefreshListener listener) {
|
||||||
super(settings);
|
|
||||||
file = resolveFile(settings, env);
|
file = resolveFile(settings, env);
|
||||||
esUsers = parseFile(file, logger);
|
esUsers = parseFile(file, logger);
|
||||||
if (esUsers.isEmpty() && logger.isDebugEnabled()) {
|
if (esUsers.isEmpty() && logger.isDebugEnabled()) {
|
||||||
@ -83,7 +82,7 @@ public class FileUserPasswdStore extends AbstractComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Path resolveFile(Settings settings, Environment env) {
|
public static Path resolveFile(Settings settings, Environment env) {
|
||||||
String location = settings.get("shield.authc.esusers.files.users");
|
String location = settings.get("files.users");
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
return ShieldPlugin.resolveConfigFile(env, "users");
|
return ShieldPlugin.resolveConfigFile(env, "users");
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,13 @@ import org.elasticsearch.ElasticsearchException;
|
|||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.base.Charsets;
|
import org.elasticsearch.common.base.Charsets;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.inject.internal.Nullable;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.shield.authc.support.RefreshListener;
|
|
||||||
import org.elasticsearch.shield.ShieldPlugin;
|
import org.elasticsearch.shield.ShieldPlugin;
|
||||||
|
import org.elasticsearch.shield.authc.support.RefreshListener;
|
||||||
import org.elasticsearch.watcher.FileChangesListener;
|
import org.elasticsearch.watcher.FileChangesListener;
|
||||||
import org.elasticsearch.watcher.FileWatcher;
|
import org.elasticsearch.watcher.FileWatcher;
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
@ -35,23 +34,21 @@ import java.util.regex.Pattern;
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class FileUserRolesStore extends AbstractComponent {
|
public class FileUserRolesStore {
|
||||||
|
|
||||||
|
private static final ESLogger logger = Loggers.getLogger(FileUserPasswdStore.class);
|
||||||
|
|
||||||
private static final Pattern USERS_DELIM = Pattern.compile("\\s*,\\s*");
|
private static final Pattern USERS_DELIM = Pattern.compile("\\s*,\\s*");
|
||||||
|
|
||||||
private final Path file;
|
private final Path file;
|
||||||
|
private CopyOnWriteArrayList<RefreshListener> listeners;
|
||||||
private volatile ImmutableMap<String, String[]> userRoles;
|
private volatile ImmutableMap<String, String[]> userRoles;
|
||||||
|
|
||||||
private CopyOnWriteArrayList<RefreshListener> listeners;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public FileUserRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
public FileUserRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService) {
|
||||||
this(settings, env, watcherService, null);
|
this(settings, env, watcherService, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUserRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService, RefreshListener listener) {
|
FileUserRolesStore(Settings settings, Environment env, ResourceWatcherService watcherService, RefreshListener listener) {
|
||||||
super(settings);
|
|
||||||
file = resolveFile(settings, env);
|
file = resolveFile(settings, env);
|
||||||
userRoles = parseFile(file, logger);
|
userRoles = parseFile(file, logger);
|
||||||
FileWatcher watcher = new FileWatcher(file.getParent().toFile());
|
FileWatcher watcher = new FileWatcher(file.getParent().toFile());
|
||||||
@ -76,7 +73,7 @@ public class FileUserRolesStore extends AbstractComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Path resolveFile(Settings settings, Environment env) {
|
public static Path resolveFile(Settings settings, Environment env) {
|
||||||
String location = settings.get("shield.authc.esusers.files.users_roles");
|
String location = settings.get("files.users_roles");
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
return ShieldPlugin.resolveConfigFile(env, "users_roles");
|
return ShieldPlugin.resolveConfigFile(env, "users_roles");
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ import org.elasticsearch.common.collect.*;
|
|||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
|
import org.elasticsearch.shield.authc.Realms;
|
||||||
|
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
||||||
import org.elasticsearch.shield.authc.esusers.FileUserPasswdStore;
|
import org.elasticsearch.shield.authc.esusers.FileUserPasswdStore;
|
||||||
import org.elasticsearch.shield.authc.esusers.FileUserRolesStore;
|
import org.elasticsearch.shield.authc.esusers.FileUserRolesStore;
|
||||||
import org.elasticsearch.shield.authc.support.Hasher;
|
import org.elasticsearch.shield.authc.support.Hasher;
|
||||||
@ -121,8 +123,9 @@ public class ESUsersTool extends CliTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||||
|
Settings esusersSettings = Realms.internalRealmSettings(settings, ESUsersRealm.TYPE);
|
||||||
verifyRoles(terminal, settings, env, roles);
|
verifyRoles(terminal, settings, env, roles);
|
||||||
Path file = FileUserPasswdStore.resolveFile(settings, env);
|
Path file = FileUserPasswdStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
||||||
if (users.containsKey(username)) {
|
if (users.containsKey(username)) {
|
||||||
terminal.println("User [%s] already exists", username);
|
terminal.println("User [%s] already exists", username);
|
||||||
@ -133,7 +136,7 @@ public class ESUsersTool extends CliTool {
|
|||||||
FileUserPasswdStore.writeFile(users, file);
|
FileUserPasswdStore.writeFile(users, file);
|
||||||
|
|
||||||
if (roles != null && roles.length > 0) {
|
if (roles != null && roles.length > 0) {
|
||||||
file = FileUserRolesStore.resolveFile(settings, env);
|
file = FileUserRolesStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, String[]> userRoles = new HashMap<>(FileUserRolesStore.parseFile(file, null));
|
Map<String, String[]> userRoles = new HashMap<>(FileUserRolesStore.parseFile(file, null));
|
||||||
userRoles.put(username, roles);
|
userRoles.put(username, roles);
|
||||||
FileUserRolesStore.writeFile(userRoles, file);
|
FileUserRolesStore.writeFile(userRoles, file);
|
||||||
@ -166,7 +169,8 @@ public class ESUsersTool extends CliTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||||
Path file = FileUserPasswdStore.resolveFile(settings, env);
|
Settings esusersSettings = Realms.internalRealmSettings(settings, ESUsersRealm.TYPE);
|
||||||
|
Path file = FileUserPasswdStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
||||||
if (!users.containsKey(username)) {
|
if (!users.containsKey(username)) {
|
||||||
terminal.println("User [%s] doesn't exist", username);
|
terminal.println("User [%s] doesn't exist", username);
|
||||||
@ -180,7 +184,7 @@ public class ESUsersTool extends CliTool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
file = FileUserRolesStore.resolveFile(settings, env);
|
file = FileUserRolesStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, String[]> userRoles = new HashMap<>(FileUserRolesStore.parseFile(file, null));
|
Map<String, String[]> userRoles = new HashMap<>(FileUserRolesStore.parseFile(file, null));
|
||||||
if (Files.exists(file)) {
|
if (Files.exists(file)) {
|
||||||
String[] roles = userRoles.remove(username);
|
String[] roles = userRoles.remove(username);
|
||||||
@ -234,7 +238,8 @@ public class ESUsersTool extends CliTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||||
Path file = FileUserPasswdStore.resolveFile(settings, env);
|
Settings esusersSettings = Realms.internalRealmSettings(settings, ESUsersRealm.TYPE);
|
||||||
|
Path file = FileUserPasswdStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
Map<String, char[]> users = new HashMap<>(FileUserPasswdStore.parseFile(file, null));
|
||||||
if (!users.containsKey(username)) {
|
if (!users.containsKey(username)) {
|
||||||
terminal.println("User [%s] doesn't exist", username);
|
terminal.println("User [%s] doesn't exist", username);
|
||||||
@ -302,14 +307,16 @@ public class ESUsersTool extends CliTool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Path path = FileUserPasswdStore.resolveFile(settings, env);
|
Settings esusersSettings = Realms.internalRealmSettings(settings, ESUsersRealm.TYPE);
|
||||||
|
|
||||||
|
Path path = FileUserPasswdStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, char[]> usersMap = FileUserPasswdStore.parseFile(path, null);
|
Map<String, char[]> usersMap = FileUserPasswdStore.parseFile(path, null);
|
||||||
if (!usersMap.containsKey(username)) {
|
if (!usersMap.containsKey(username)) {
|
||||||
terminal.println("User [%s] doesn't exist", username);
|
terminal.println("User [%s] doesn't exist", username);
|
||||||
return ExitStatus.NO_USER;
|
return ExitStatus.NO_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path file = FileUserRolesStore.resolveFile(settings, env);
|
Path file = FileUserRolesStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, String[]> userRoles = FileUserRolesStore.parseFile(file, null);
|
Map<String, String[]> userRoles = FileUserRolesStore.parseFile(file, null);
|
||||||
|
|
||||||
List<String> roles = Lists.newArrayList();
|
List<String> roles = Lists.newArrayList();
|
||||||
@ -353,10 +360,11 @@ public class ESUsersTool extends CliTool {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
public ExitStatus execute(Settings settings, Environment env) throws Exception {
|
||||||
|
Settings esusersSettings = Realms.internalRealmSettings(settings, ESUsersRealm.TYPE);
|
||||||
ImmutableMap<String, Permission.Global.Role> knownRoles = loadRoles(terminal, settings, env);
|
ImmutableMap<String, Permission.Global.Role> knownRoles = loadRoles(terminal, settings, env);
|
||||||
Path userRolesFilePath = FileUserRolesStore.resolveFile(settings, env);
|
Path userRolesFilePath = FileUserRolesStore.resolveFile(esusersSettings, env);
|
||||||
Map<String, String[]> userRoles = FileUserRolesStore.parseFile(userRolesFilePath, null);
|
Map<String, String[]> userRoles = FileUserRolesStore.parseFile(userRolesFilePath, null);
|
||||||
Path userFilePath = FileUserPasswdStore.resolveFile(settings, env);
|
Path userFilePath = FileUserPasswdStore.resolveFile(esusersSettings, env);
|
||||||
Set<String> users = FileUserPasswdStore.parseFile(userFilePath, null).keySet();
|
Set<String> users = FileUserPasswdStore.parseFile(userFilePath, null).keySet();
|
||||||
|
|
||||||
if (username != null) {
|
if (username != null) {
|
||||||
@ -372,7 +380,7 @@ public class ESUsersTool extends CliTool {
|
|||||||
terminal.println("%-15s: %s", username, Joiner.on(",").useForNull("-").join(markedRoles));
|
terminal.println("%-15s: %s", username, Joiner.on(",").useForNull("-").join(markedRoles));
|
||||||
if (!unknownRoles.isEmpty()) {
|
if (!unknownRoles.isEmpty()) {
|
||||||
// at least one role is marked... so printing the legend
|
// at least one role is marked... so printing the legend
|
||||||
Path rolesFile = FileRolesStore.resolveFile(settings, env).toAbsolutePath();
|
Path rolesFile = FileRolesStore.resolveFile(esusersSettings, env).toAbsolutePath();
|
||||||
terminal.println();
|
terminal.println();
|
||||||
terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath());
|
terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath());
|
||||||
}
|
}
|
||||||
@ -397,7 +405,7 @@ public class ESUsersTool extends CliTool {
|
|||||||
|
|
||||||
if (unknownRolesFound) {
|
if (unknownRolesFound) {
|
||||||
// at least one role is marked... so printing the legend
|
// at least one role is marked... so printing the legend
|
||||||
Path rolesFile = FileRolesStore.resolveFile(settings, env).toAbsolutePath();
|
Path rolesFile = FileRolesStore.resolveFile(esusersSettings, env).toAbsolutePath();
|
||||||
terminal.println();
|
terminal.println();
|
||||||
terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath());
|
terminal.println(" [*] An unknown role. Please check [%s] to see available roles", rolesFile.toAbsolutePath());
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ package org.elasticsearch.shield.authc.ldap;
|
|||||||
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.ShieldSettingsException;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
@ -26,11 +25,11 @@ import java.util.Hashtable;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* This factory creates LDAP connections via iterating through user templates.
|
* This factory creates LDAP connections via iterating through user templates.
|
||||||
* <p/>
|
*
|
||||||
* Note that even though there is a separate factory for Active Directory, this factory would work against AD. A template
|
* Note that even though there is a separate factory for Active Directory, this factory would work against AD. A template
|
||||||
* for each user context would need to be supplied.
|
* for each user context would need to be supplied.
|
||||||
*/
|
*/
|
||||||
public class LdapConnectionFactory extends AbstractComponent implements ConnectionFactory {
|
public class LdapConnectionFactory extends ConnectionFactory {
|
||||||
|
|
||||||
public static final String USER_DN_TEMPLATES_SETTING = "user_dn_templates";
|
public static final String USER_DN_TEMPLATES_SETTING = "user_dn_templates";
|
||||||
public static final String GROUP_SEARCH_SUBTREE_SETTING = "group_search.subtree_search";
|
public static final String GROUP_SEARCH_SUBTREE_SETTING = "group_search.subtree_search";
|
||||||
@ -45,11 +44,11 @@ public class LdapConnectionFactory extends AbstractComponent implements Connecti
|
|||||||
@Inject
|
@Inject
|
||||||
public LdapConnectionFactory(Settings settings) {
|
public LdapConnectionFactory(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
userDnTemplates = componentSettings.getAsArray(USER_DN_TEMPLATES_SETTING);
|
userDnTemplates = settings.getAsArray(USER_DN_TEMPLATES_SETTING);
|
||||||
if (userDnTemplates == null) {
|
if (userDnTemplates == null) {
|
||||||
throw new ShieldSettingsException("Missing required ldap setting [" + USER_DN_TEMPLATES_SETTING + "]");
|
throw new ShieldSettingsException("Missing required ldap setting [" + USER_DN_TEMPLATES_SETTING + "]");
|
||||||
}
|
}
|
||||||
String[] ldapUrls = componentSettings.getAsArray(URLS_SETTING);
|
String[] ldapUrls = settings.getAsArray(URLS_SETTING);
|
||||||
if (ldapUrls == null) {
|
if (ldapUrls == null) {
|
||||||
throw new ShieldSettingsException("Missing required ldap setting [" + URLS_SETTING + "]");
|
throw new ShieldSettingsException("Missing required ldap setting [" + URLS_SETTING + "]");
|
||||||
}
|
}
|
||||||
@ -62,9 +61,9 @@ public class LdapConnectionFactory extends AbstractComponent implements Connecti
|
|||||||
LdapSslSocketFactory.configureJndiSSL(ldapUrls, builder);
|
LdapSslSocketFactory.configureJndiSSL(ldapUrls, builder);
|
||||||
|
|
||||||
sharedLdapEnv = builder.build();
|
sharedLdapEnv = builder.build();
|
||||||
groupSearchDN = componentSettings.get(GROUP_SEARCH_BASEDN_SETTING);
|
groupSearchDN = settings.get(GROUP_SEARCH_BASEDN_SETTING);
|
||||||
findGroupsByAttribute = groupSearchDN == null;
|
findGroupsByAttribute = groupSearchDN == null;
|
||||||
groupSubTreeSearch = componentSettings.getAsBoolean(GROUP_SEARCH_SUBTREE_SETTING, false);
|
groupSubTreeSearch = settings.getAsBoolean(GROUP_SEARCH_SUBTREE_SETTING, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.ldap;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
|
||||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures Ldap object injections
|
|
||||||
*/
|
|
||||||
public class LdapModule extends AbstractShieldModule.Node {
|
|
||||||
|
|
||||||
private final boolean enabled;
|
|
||||||
|
|
||||||
public LdapModule(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
enabled = enabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configureNode() {
|
|
||||||
if (enabled) {
|
|
||||||
/* This socket factory needs to be configured before any LDAP connections are created. LDAP configuration
|
|
||||||
for JNDI invokes a static getSocketFactory method from LdapSslSocketFactory. */
|
|
||||||
requestStaticInjection(LdapSslSocketFactory.class);
|
|
||||||
|
|
||||||
bind(LdapRealm.class).asEagerSingleton();
|
|
||||||
} else {
|
|
||||||
bind(LdapRealm.class).toProvider(Providers.<LdapRealm>of(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean enabled(Settings settings) {
|
|
||||||
Settings authcSettings = settings.getAsSettings("shield.authc");
|
|
||||||
if (!authcSettings.names().contains(LdapRealm.TYPE)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Settings ldapSettings = authcSettings.getAsSettings(LdapRealm.TYPE);
|
|
||||||
return ldapSettings.getAsBoolean("enabled", true);
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,8 +7,10 @@ package org.elasticsearch.shield.authc.ldap;
|
|||||||
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapRealm;
|
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapRealm;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates username/password tokens against ldap, locates groups and maps them to roles.
|
* Authenticates username/password tokens against ldap, locates groups and maps them to roles.
|
||||||
@ -18,12 +20,32 @@ public class LdapRealm extends AbstractLdapRealm {
|
|||||||
public static final String TYPE = "ldap";
|
public static final String TYPE = "ldap";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public LdapRealm(Settings settings, LdapConnectionFactory ldap, LdapGroupToRoleMapper roleMapper, RestController restController) {
|
public LdapRealm(String name, Settings settings, LdapConnectionFactory ldap, LdapGroupToRoleMapper roleMapper) {
|
||||||
super(settings, ldap, roleMapper, restController);
|
super(name, TYPE, settings, ldap, roleMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return TYPE;
|
return TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Factory extends AbstractLdapRealm.Factory<LdapRealm> {
|
||||||
|
|
||||||
|
private final Environment env;
|
||||||
|
private final ResourceWatcherService watcherService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Factory(Environment env, ResourceWatcherService watcherService, RestController restController) {
|
||||||
|
super(TYPE, restController);
|
||||||
|
this.env = env;
|
||||||
|
this.watcherService = watcherService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LdapRealm create(String name, Settings settings) {
|
||||||
|
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(settings);
|
||||||
|
LdapGroupToRoleMapper roleMapper = new LdapGroupToRoleMapper(settings, env, watcherService);
|
||||||
|
return new LdapRealm(name, settings, connectionFactory, roleMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,22 +7,17 @@ package org.elasticsearch.shield.authc.support;
|
|||||||
|
|
||||||
import org.elasticsearch.common.cache.Cache;
|
import org.elasticsearch.common.cache.Cache;
|
||||||
import org.elasticsearch.common.cache.CacheBuilder;
|
import org.elasticsearch.common.cache.CacheBuilder;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.util.concurrent.UncheckedExecutionException;
|
import org.elasticsearch.common.util.concurrent.UncheckedExecutionException;
|
||||||
import org.elasticsearch.rest.RestRequest;
|
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
import org.elasticsearch.shield.authc.AuthenticationException;
|
import org.elasticsearch.shield.authc.AuthenticationException;
|
||||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
|
||||||
import org.elasticsearch.shield.authc.Realm;
|
|
||||||
import org.elasticsearch.transport.TransportMessage;
|
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public abstract class CachingUsernamePasswordRealm extends AbstractComponent implements Realm<UsernamePasswordToken> {
|
public abstract class CachingUsernamePasswordRealm extends UsernamePasswordRealm {
|
||||||
|
|
||||||
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueHours(1);
|
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueHours(1);
|
||||||
private static final int DEFAULT_MAX_USERS = 100000; //100k users
|
private static final int DEFAULT_MAX_USERS = 100000; //100k users
|
||||||
@ -30,13 +25,12 @@ public abstract class CachingUsernamePasswordRealm extends AbstractComponent imp
|
|||||||
public static final String CACHE_MAX_USERS = "cache.max_users";
|
public static final String CACHE_MAX_USERS = "cache.max_users";
|
||||||
|
|
||||||
private final Cache<String, UserWithHash> cache;
|
private final Cache<String, UserWithHash> cache;
|
||||||
|
|
||||||
private final Hasher hasher;
|
private final Hasher hasher;
|
||||||
|
|
||||||
protected CachingUsernamePasswordRealm(Settings settings) {
|
protected CachingUsernamePasswordRealm(String type, String name, Settings settings) {
|
||||||
super(settings);
|
super(type, name, settings);
|
||||||
hasher = Hasher.resolve(componentSettings.get("cache.hash_algo", null), Hasher.SHA2);
|
hasher = Hasher.resolve(settings.get("cache.hash_algo", null), Hasher.SHA2);
|
||||||
TimeValue ttl = componentSettings.getAsTime(CACHE_TTL, DEFAULT_TTL);
|
TimeValue ttl = settings.getAsTime(CACHE_TTL, DEFAULT_TTL);
|
||||||
if (ttl.millis() > 0) {
|
if (ttl.millis() > 0) {
|
||||||
cache = CacheBuilder.newBuilder()
|
cache = CacheBuilder.newBuilder()
|
||||||
.expireAfterWrite(ttl.getMillis(), TimeUnit.MILLISECONDS)
|
.expireAfterWrite(ttl.getMillis(), TimeUnit.MILLISECONDS)
|
||||||
@ -47,21 +41,6 @@ public abstract class CachingUsernamePasswordRealm extends AbstractComponent imp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public UsernamePasswordToken token(RestRequest request) {
|
|
||||||
return UsernamePasswordToken.extractToken(request, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UsernamePasswordToken token(TransportMessage<?> message) {
|
|
||||||
return UsernamePasswordToken.extractToken(message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(AuthenticationToken token) {
|
|
||||||
return token instanceof UsernamePasswordToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void expire(String username) {
|
protected final void expire(String username) {
|
||||||
if (cache != null) {
|
if (cache != null) {
|
||||||
cache.invalidate(username);
|
cache.invalidate(username);
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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.authc.support;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.shield.authc.AuthenticationToken;
|
||||||
|
import org.elasticsearch.shield.authc.Realm;
|
||||||
|
import org.elasticsearch.transport.TransportMessage;
|
||||||
|
|
||||||
|
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class UsernamePasswordRealm extends Realm<UsernamePasswordToken> {
|
||||||
|
|
||||||
|
public UsernamePasswordRealm(String type, String name, Settings settings) {
|
||||||
|
super(type, name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UsernamePasswordToken token(RestRequest request) {
|
||||||
|
return UsernamePasswordToken.extractToken(request, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UsernamePasswordToken token(TransportMessage<?> message) {
|
||||||
|
return UsernamePasswordToken.extractToken(message, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supports(AuthenticationToken token) {
|
||||||
|
return token instanceof UsernamePasswordToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class Factory<R extends UsernamePasswordRealm> extends Realm.Factory<R> {
|
||||||
|
|
||||||
|
protected Factory(String type, boolean internal, RestController restController) {
|
||||||
|
super(type, internal);
|
||||||
|
restController.registerRelevantHeaders(BASIC_AUTH_HEADER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,13 +8,13 @@ package org.elasticsearch.shield.authc.support.ldap;
|
|||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.shield.authc.support.RefreshListener;
|
|
||||||
import org.elasticsearch.shield.ShieldPlugin;
|
import org.elasticsearch.shield.ShieldPlugin;
|
||||||
|
import org.elasticsearch.shield.authc.support.RefreshListener;
|
||||||
import org.elasticsearch.watcher.FileChangesListener;
|
import org.elasticsearch.watcher.FileChangesListener;
|
||||||
import org.elasticsearch.watcher.FileWatcher;
|
import org.elasticsearch.watcher.FileWatcher;
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
@ -33,12 +33,14 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
/**
|
/**
|
||||||
* This class loads and monitors the file defining the mappings of LDAP Group DNs to internal ES Roles.
|
* This class loads and monitors the file defining the mappings of LDAP Group DNs to internal ES Roles.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractGroupToRoleMapper extends AbstractComponent {
|
public abstract class AbstractGroupToRoleMapper {
|
||||||
|
|
||||||
public static final String DEFAULT_FILE_NAME = "role_mapping.yml";
|
public static final String DEFAULT_FILE_NAME = "role_mapping.yml";
|
||||||
public static final String ROLE_MAPPING_FILE_SETTING = "files.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";
|
public static final String USE_UNMAPPED_GROUPS_AS_ROLES_SETTING = "unmapped_groups_as_roles";
|
||||||
|
|
||||||
|
protected final ESLogger logger = Loggers.getLogger(getClass());
|
||||||
|
protected final Settings settings;
|
||||||
private final Path file;
|
private final Path file;
|
||||||
private final boolean useUnmappedGroupsAsRoles;
|
private final boolean useUnmappedGroupsAsRoles;
|
||||||
private final String realmType;
|
private final String realmType;
|
||||||
@ -48,10 +50,10 @@ public abstract class AbstractGroupToRoleMapper extends AbstractComponent {
|
|||||||
|
|
||||||
protected AbstractGroupToRoleMapper(Settings settings, String realmType, Environment env,
|
protected AbstractGroupToRoleMapper(Settings settings, String realmType, Environment env,
|
||||||
ResourceWatcherService watcherService, @Nullable RefreshListener listener) {
|
ResourceWatcherService watcherService, @Nullable RefreshListener listener) {
|
||||||
super(settings);
|
this.settings = settings;
|
||||||
this.realmType = realmType;
|
this.realmType = realmType;
|
||||||
useUnmappedGroupsAsRoles = componentSettings.getAsBoolean(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, false);
|
useUnmappedGroupsAsRoles = settings.getAsBoolean(USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, false);
|
||||||
file = resolveFile(componentSettings, env);
|
file = resolveFile(settings, env);
|
||||||
groupRoles = parseFile(file, logger, realmType);
|
groupRoles = parseFile(file, logger, realmType);
|
||||||
FileWatcher watcher = new FileWatcher(file.getParent().toFile());
|
FileWatcher watcher = new FileWatcher(file.getParent().toFile());
|
||||||
watcher.addListener(new FileListener());
|
watcher.addListener(new FileListener());
|
||||||
|
@ -9,42 +9,28 @@ import org.elasticsearch.common.settings.Settings;
|
|||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.shield.ShieldException;
|
import org.elasticsearch.shield.ShieldException;
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
import org.elasticsearch.shield.authc.AuthenticationToken;
|
|
||||||
import org.elasticsearch.shield.authc.Realm;
|
|
||||||
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
|
import org.elasticsearch.shield.authc.support.CachingUsernamePasswordRealm;
|
||||||
import org.elasticsearch.shield.authc.support.RefreshListener;
|
import org.elasticsearch.shield.authc.support.RefreshListener;
|
||||||
|
import org.elasticsearch.shield.authc.support.UsernamePasswordRealm;
|
||||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||||
import org.elasticsearch.transport.TransportMessage;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supporting class for JNDI-based Realms
|
* Supporting class for JNDI-based Realms
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm implements Realm<UsernamePasswordToken> {
|
public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm {
|
||||||
|
|
||||||
protected final ConnectionFactory connectionFactory;
|
protected final ConnectionFactory connectionFactory;
|
||||||
protected final AbstractGroupToRoleMapper roleMapper;
|
protected final AbstractGroupToRoleMapper roleMapper;
|
||||||
|
|
||||||
protected AbstractLdapRealm(Settings settings, ConnectionFactory connectionFactory,
|
protected AbstractLdapRealm(String type, String name, Settings settings,
|
||||||
AbstractGroupToRoleMapper roleMapper, RestController restController) {
|
ConnectionFactory connectionFactory, AbstractGroupToRoleMapper roleMapper) {
|
||||||
super(settings);
|
super(type, name, settings);
|
||||||
this.connectionFactory = connectionFactory;
|
this.connectionFactory = connectionFactory;
|
||||||
this.roleMapper = roleMapper;
|
this.roleMapper = roleMapper;
|
||||||
roleMapper.addListener(new Listener());
|
roleMapper.addListener(new Listener());
|
||||||
restController.registerRelevantHeaders(BASIC_AUTH_HEADER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UsernamePasswordToken token(TransportMessage<?> message) {
|
|
||||||
return UsernamePasswordToken.extractToken(message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean supports(AuthenticationToken token) {
|
|
||||||
return token instanceof UsernamePasswordToken;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -72,4 +58,21 @@ public abstract class AbstractLdapRealm extends CachingUsernamePasswordRealm imp
|
|||||||
expireAll();
|
expireAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static abstract class Factory<R extends AbstractLdapRealm> extends UsernamePasswordRealm.Factory<R> {
|
||||||
|
|
||||||
|
public Factory(String type, RestController restController) {
|
||||||
|
super(type, false, restController);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAP realms require minimum settings (e.g. URL), therefore they'll never create a default.
|
||||||
|
*
|
||||||
|
* @return {@code null} always
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final R createDefault(String name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc.support.ldap;
|
package org.elasticsearch.shield.authc.support.ldap;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,9 +22,16 @@ import org.elasticsearch.shield.authc.support.SecuredString;
|
|||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
*/
|
*/
|
||||||
public interface ConnectionFactory {
|
public abstract class ConnectionFactory {
|
||||||
|
|
||||||
static final String URLS_SETTING = "url";
|
public static final String URLS_SETTING = "url";
|
||||||
|
|
||||||
|
protected final ESLogger logger = Loggers.getLogger(getClass());
|
||||||
|
private final Settings settings;
|
||||||
|
|
||||||
|
protected ConnectionFactory(Settings settings) {
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates the given user and opens a new connection that bound to it (meaning, all operations
|
* Authenticates the given user and opens a new connection that bound to it (meaning, all operations
|
||||||
@ -30,6 +40,6 @@ public interface ConnectionFactory {
|
|||||||
* @param user The name of the user to authenticate the connection with.
|
* @param user The name of the user to authenticate the connection with.
|
||||||
* @param password The password of the user
|
* @param password The password of the user
|
||||||
*/
|
*/
|
||||||
AbstractLdapConnection open(String user, SecuredString password) ;
|
public abstract AbstractLdapConnection open(String user, SecuredString password) ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc.support.ldap;
|
package org.elasticsearch.shield.authc.support.ldap;
|
||||||
|
|
||||||
import org.elasticsearch.common.Nullable;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.inject.Provider;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.logging.ESLoggerFactory;
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.shield.ShieldSettingsException;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
import org.elasticsearch.shield.ssl.SSLService;
|
import org.elasticsearch.shield.ssl.SSLService;
|
||||||
|
|
||||||
@ -35,34 +35,32 @@ import static org.elasticsearch.common.collect.Iterables.all;
|
|||||||
*/
|
*/
|
||||||
public class LdapSslSocketFactory extends SocketFactory {
|
public class LdapSslSocketFactory extends SocketFactory {
|
||||||
|
|
||||||
|
private static ESLogger logger = Loggers.getLogger(LdapSslSocketFactory.class);
|
||||||
|
|
||||||
static final String JAVA_NAMING_LDAP_FACTORY_SOCKET = "java.naming.ldap.factory.socket";
|
static final String JAVA_NAMING_LDAP_FACTORY_SOCKET = "java.naming.ldap.factory.socket";
|
||||||
private static final Pattern STARTS_WITH_LDAPS = Pattern.compile("^ldaps:.*", Pattern.CASE_INSENSITIVE);
|
private static final Pattern STARTS_WITH_LDAPS = Pattern.compile("^ldaps:.*", Pattern.CASE_INSENSITIVE);
|
||||||
private static final Pattern STARTS_WITH_LDAP = Pattern.compile("^ldap:.*", Pattern.CASE_INSENSITIVE);
|
private static final Pattern STARTS_WITH_LDAP = Pattern.compile("^ldap:.*", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
private static ESLogger logger = ESLoggerFactory.getLogger(LdapSslSocketFactory.class.getName());
|
|
||||||
|
|
||||||
private static LdapSslSocketFactory instance;
|
private static LdapSslSocketFactory instance;
|
||||||
|
|
||||||
|
private static Provider<SSLService> sslServiceProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This should only be invoked once to establish a static instance that will be used for each constructor.
|
* This should only be invoked once to establish a static instance that will be used for each constructor.
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public static void init(@Nullable SSLService ssl) {
|
public static void init(Provider<SSLService> sslServiceProvider) {
|
||||||
if (instance != null) {
|
LdapSslSocketFactory.sslServiceProvider = sslServiceProvider;
|
||||||
logger.error("LdapSslSocketFactory already configured, this change could lead to threading issues");
|
|
||||||
}
|
|
||||||
if (ssl == null) {
|
|
||||||
logger.warn("no keystore has been configured for LDAP");
|
|
||||||
} else {
|
|
||||||
instance = new LdapSslSocketFactory(ssl.getSSLSocketFactory());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This clears the static factory. There are threading issues with this. But for
|
* This clears the static factory. There are threading issues with this. But for
|
||||||
* testing this is useful.
|
* testing this is useful.
|
||||||
|
*
|
||||||
|
* WARNING: THIS METHOD SHOULD ONLY BE CALLED IN TESTS!!!!
|
||||||
|
*
|
||||||
|
* TODO: find a way to change the tests such that we can remove this method
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
logger.error("clear should only be called by tests");
|
logger.error("clear should only be called by tests");
|
||||||
instance = null;
|
instance = null;
|
||||||
@ -73,8 +71,10 @@ public class LdapSslSocketFactory extends SocketFactory {
|
|||||||
*
|
*
|
||||||
* @return a singleton instance of LdapSslSocketFactory set by calling the init static method.
|
* @return a singleton instance of LdapSslSocketFactory set by calling the init static method.
|
||||||
*/
|
*/
|
||||||
public static SocketFactory getDefault() {
|
public static synchronized SocketFactory getDefault() {
|
||||||
assert instance != null;
|
if (instance == null) {
|
||||||
|
instance = new LdapSslSocketFactory(sslServiceProvider.get().getSSLSocketFactory());
|
||||||
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,23 +87,23 @@ public class LdapSslSocketFactory extends SocketFactory {
|
|||||||
//The following methods are all wrappers around the instance of socketFactory
|
//The following methods are all wrappers around the instance of socketFactory
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Socket createSocket(String s, int i) throws IOException {
|
public Socket createSocket(String host, int port) throws IOException {
|
||||||
return socketFactory.createSocket(s, i);
|
return socketFactory.createSocket(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Socket createSocket(String s, int i, InetAddress inetAddress, int i2) throws IOException {
|
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||||
return socketFactory.createSocket(s, i, inetAddress, i2);
|
return socketFactory.createSocket(host, port, localHost, localPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Socket createSocket(InetAddress inetAddress, int i) throws IOException {
|
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||||
return socketFactory.createSocket(inetAddress, i);
|
return socketFactory.createSocket(host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress2, int i2) throws IOException {
|
public Socket createSocket(InetAddress host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||||
return socketFactory.createSocket(inetAddress, i, inetAddress2, i2);
|
return socketFactory.createSocket(host, port, localHost, localPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,12 +115,12 @@ public class LdapSslSocketFactory extends SocketFactory {
|
|||||||
*/
|
*/
|
||||||
public static void configureJndiSSL(String[] ldapUrls, ImmutableMap.Builder<String, Serializable> builder) {
|
public static void configureJndiSSL(String[] ldapUrls, ImmutableMap.Builder<String, Serializable> builder) {
|
||||||
boolean secureProtocol = secureUrls(ldapUrls);
|
boolean secureProtocol = secureUrls(ldapUrls);
|
||||||
if (secureProtocol && instance != null) {
|
if (secureProtocol) {
|
||||||
builder.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, LdapSslSocketFactory.class.getName());
|
builder.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, LdapSslSocketFactory.class.getName());
|
||||||
} else {
|
} else {
|
||||||
logger.warn("LdapSslSocketFactory not used for LDAP connections");
|
logger.warn("LdapSslSocketFactory not used for LDAP connections");
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("LdapSslSocketFactory: secureProtocol = [{}], instance != null [{}]", secureProtocol, instance != null);
|
logger.debug("LdapSslSocketFactory: secureProtocol = [{}]", secureProtocol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.ssl;
|
package org.elasticsearch.shield.ssl;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.Scopes;
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
import org.elasticsearch.common.inject.util.Providers;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.support.AbstractShieldModule;
|
import org.elasticsearch.shield.support.AbstractShieldModule;
|
||||||
@ -20,10 +21,6 @@ public class SSLModule extends AbstractShieldModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(boolean clientMode) {
|
protected void configure(boolean clientMode) {
|
||||||
if (SSLService.isSSLEnabled(settings)) {
|
bind(SSLService.class).in(Scopes.SINGLETON);
|
||||||
bind(SSLService.class).asEagerSingleton();
|
|
||||||
} else {
|
|
||||||
bind(SSLService.class).toProvider(Providers.<SSLService>of(null));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ import org.elasticsearch.common.component.AbstractComponent;
|
|||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.ShieldSettingsException;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
import org.elasticsearch.shield.authc.ldap.LdapModule;
|
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -25,9 +23,6 @@ import java.util.Arrays;
|
|||||||
public class SSLService extends AbstractComponent {
|
public class SSLService extends AbstractComponent {
|
||||||
|
|
||||||
static final String[] DEFAULT_CIPHERS = new String[]{ "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
|
static final String[] DEFAULT_CIPHERS = new String[]{ "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" };
|
||||||
public static final String SHIELD_TRANSPORT_SSL = "shield.transport.ssl";
|
|
||||||
public static final String SHIELD_HTTP_SSL = "shield.http.ssl";
|
|
||||||
public static final String SHIELD_AUTHC_LDAP_URL = "shield.authc.ldap.url";
|
|
||||||
|
|
||||||
private final TrustManagerFactory trustFactory;
|
private final TrustManagerFactory trustFactory;
|
||||||
private final KeyManagerFactory keyManagerFactory;
|
private final KeyManagerFactory keyManagerFactory;
|
||||||
@ -162,11 +157,4 @@ public class SSLService extends AbstractComponent {
|
|||||||
throw new ElasticsearchException("Failed to initialize a TrustManagerFactory", e);
|
throw new ElasticsearchException("Failed to initialize a TrustManagerFactory", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSSLEnabled(Settings settings) {
|
|
||||||
return settings.getAsBoolean(SHIELD_TRANSPORT_SSL, false) ||
|
|
||||||
settings.getAsBoolean(SHIELD_HTTP_SSL, false) ||
|
|
||||||
(LdapSslSocketFactory.secureUrls(settings.getAsArray(SHIELD_AUTHC_LDAP_URL)) &&
|
|
||||||
LdapModule.enabled(settings));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package org.elasticsearch.shield.transport.netty;
|
package org.elasticsearch.shield.transport.netty;
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.inject.Provider;
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.inject.internal.Nullable;
|
||||||
import org.elasticsearch.common.netty.channel.ChannelPipeline;
|
import org.elasticsearch.common.netty.channel.ChannelPipeline;
|
||||||
import org.elasticsearch.common.netty.channel.ChannelPipelineFactory;
|
import org.elasticsearch.common.netty.channel.ChannelPipelineFactory;
|
||||||
@ -26,18 +27,17 @@ public class NettySecuredHttpServerTransport extends NettyHttpServerTransport {
|
|||||||
|
|
||||||
private final boolean ssl;
|
private final boolean ssl;
|
||||||
private final boolean ipFilterEnabled;
|
private final boolean ipFilterEnabled;
|
||||||
private final IPFilteringN2NAuthenticator authenticator;
|
private final @Nullable IPFilteringN2NAuthenticator authenticator;
|
||||||
private final SSLService sslService;
|
private final @Nullable SSLService sslService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NettySecuredHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays,
|
public NettySecuredHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays,
|
||||||
@Nullable IPFilteringN2NAuthenticator authenticator, @Nullable SSLService sslService) {
|
@Nullable IPFilteringN2NAuthenticator authenticator, Provider<SSLService> sslServiceProvider) {
|
||||||
super(settings, networkService, bigArrays);
|
super(settings, networkService, bigArrays);
|
||||||
this.authenticator = authenticator;
|
this.authenticator = authenticator;
|
||||||
this.ssl = settings.getAsBoolean("shield.http.ssl", false);
|
this.ssl = settings.getAsBoolean("shield.http.ssl", false);
|
||||||
this.sslService = sslService;
|
|
||||||
assert !ssl || sslService != null : "ssl is enabled yet the ssl service is null";
|
|
||||||
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.filter.enabled", true);
|
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.filter.enabled", true);
|
||||||
|
this.sslService = ssl ? sslServiceProvider.get() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7,6 +7,7 @@ package org.elasticsearch.shield.transport.netty;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.inject.Provider;
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.inject.internal.Nullable;
|
||||||
import org.elasticsearch.common.netty.channel.ChannelPipeline;
|
import org.elasticsearch.common.netty.channel.ChannelPipeline;
|
||||||
import org.elasticsearch.common.netty.channel.ChannelPipelineFactory;
|
import org.elasticsearch.common.netty.channel.ChannelPipelineFactory;
|
||||||
@ -27,19 +28,18 @@ import javax.net.ssl.SSLEngine;
|
|||||||
public class NettySecuredTransport extends NettyTransport {
|
public class NettySecuredTransport extends NettyTransport {
|
||||||
|
|
||||||
private final boolean ssl;
|
private final boolean ssl;
|
||||||
private final SSLService sslService;
|
|
||||||
private final boolean ipFilterEnabled;
|
private final boolean ipFilterEnabled;
|
||||||
private final IPFilteringN2NAuthenticator authenticator;
|
private final @Nullable SSLService sslService;
|
||||||
|
private final @Nullable IPFilteringN2NAuthenticator authenticator;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public NettySecuredTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version,
|
public NettySecuredTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version,
|
||||||
@Nullable IPFilteringN2NAuthenticator authenticator, @Nullable SSLService sslService) {
|
@Nullable IPFilteringN2NAuthenticator authenticator, Provider<SSLService> sslServiceProvider) {
|
||||||
super(settings, threadPool, networkService, bigArrays, version);
|
super(settings, threadPool, networkService, bigArrays, version);
|
||||||
this.authenticator = authenticator;
|
this.authenticator = authenticator;
|
||||||
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.filter.enabled", true);
|
this.ipFilterEnabled = settings.getAsBoolean("shield.transport.filter.enabled", true);
|
||||||
this.sslService = sslService;
|
|
||||||
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
|
this.ssl = settings.getAsBoolean("shield.transport.ssl", false);
|
||||||
assert !ssl || sslService != null : "ssl is enabled yet the ssl service is null";
|
this.sslService = ssl ? sslServiceProvider.get() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc;
|
package org.elasticsearch.shield.authc;
|
||||||
|
|
||||||
|
import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.BytesStreamInput;
|
import org.elasticsearch.common.io.stream.BytesStreamInput;
|
||||||
@ -21,7 +22,10 @@ import org.junit.Before;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
@ -55,8 +59,12 @@ public class InternalAuthenticationServiceTests extends ElasticsearchTestCase {
|
|||||||
when(firstRealm.type()).thenReturn("first");
|
when(firstRealm.type()).thenReturn("first");
|
||||||
secondRealm = mock(Realm.class);
|
secondRealm = mock(Realm.class);
|
||||||
when(secondRealm.type()).thenReturn("second");
|
when(secondRealm.type()).thenReturn("second");
|
||||||
realms = mock(Realms.class);
|
realms = new Realms(ImmutableSettings.EMPTY, Collections.<String, Realm.Factory>emptyMap()) {
|
||||||
when(realms.realms()).thenReturn(new Realm[] {firstRealm, secondRealm});
|
@Override
|
||||||
|
protected List<Realm> initRealms() {
|
||||||
|
return ImmutableList.of(firstRealm, secondRealm);
|
||||||
|
}
|
||||||
|
};
|
||||||
signatureService = mock(SignatureService.class);
|
signatureService = mock(SignatureService.class);
|
||||||
|
|
||||||
auditTrail = mock(AuditTrail.class);
|
auditTrail = mock(AuditTrail.class);
|
||||||
@ -317,8 +325,8 @@ public class InternalAuthenticationServiceTests extends ElasticsearchTestCase {
|
|||||||
service = new InternalAuthenticationService(settings, realms, auditTrail, signatureService);
|
service = new InternalAuthenticationService(settings, realms, auditTrail, signatureService);
|
||||||
|
|
||||||
User user1 = new User.Simple("username", "r1", "r2");
|
User user1 = new User.Simple("username", "r1", "r2");
|
||||||
when(firstRealm.token(message)).thenReturn(token);
|
|
||||||
when(firstRealm.supports(token)).thenReturn(true);
|
when(firstRealm.supports(token)).thenReturn(true);
|
||||||
|
when(firstRealm.token(message)).thenReturn(token);
|
||||||
when(firstRealm.authenticate(token)).thenReturn(user1);
|
when(firstRealm.authenticate(token)).thenReturn(user1);
|
||||||
User user2 = service.authenticate("_action", message, User.SYSTEM);
|
User user2 = service.authenticate("_action", message, User.SYSTEM);
|
||||||
assertThat(user1, sameInstance(user2));
|
assertThat(user1, sameInstance(user2));
|
||||||
|
133
src/test/java/org/elasticsearch/shield/authc/RealmsTests.java
Normal file
133
src/test/java/org/elasticsearch/shield/authc/RealmsTests.java
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.authc;
|
||||||
|
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
|
import org.elasticsearch.shield.User;
|
||||||
|
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
||||||
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.elasticsearch.transport.TransportMessage;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RealmsTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
|
private Map<String, Realm.Factory> factories;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
factories = new HashMap<>();
|
||||||
|
factories.put("esusers", new DummyRealm.Factory("esusers", true));
|
||||||
|
for (int i = 0; i < randomIntBetween(1, 5); i++) {
|
||||||
|
DummyRealm.Factory factory = new DummyRealm.Factory("type_" + i, rarely());
|
||||||
|
factories.put("type_" + i, factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithSettings() throws Exception {
|
||||||
|
ImmutableSettings.Builder builder = ImmutableSettings.builder();
|
||||||
|
List<Integer> orders = new ArrayList<>(factories.size() - 1);
|
||||||
|
for (int i = 0; i < factories.size() - 1; i++) {
|
||||||
|
orders.add(i);
|
||||||
|
}
|
||||||
|
Collections.shuffle(orders);
|
||||||
|
Map<Integer, Integer> orderToIndex = new HashMap<>();
|
||||||
|
for (int i = 0; i < factories.size() - 1; i++) {
|
||||||
|
builder.put("shield.authc.realms.realm_" + i + ".type", "type_" + i);
|
||||||
|
builder.put("shield.authc.realms.realm_" + i + ".order", orders.get(i));
|
||||||
|
orderToIndex.put(orders.get(i), i);
|
||||||
|
}
|
||||||
|
Realms realms = new Realms(builder.build(), factories);
|
||||||
|
int i = 0;
|
||||||
|
for (Realm realm : realms) {
|
||||||
|
assertThat(realm.order(), equalTo(i));
|
||||||
|
int index = orderToIndex.get(i);
|
||||||
|
assertThat(realm.type(), equalTo("type_" + index));
|
||||||
|
assertThat(realm.name(), equalTo("realm_" + index));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ShieldSettingsException.class)
|
||||||
|
public void testWithSettings_WithMultipleInternalRealmsOfSameType() throws Exception {
|
||||||
|
ImmutableSettings.Builder builder = ImmutableSettings.builder();
|
||||||
|
builder.put("shield.authc.realms.realm_1.type", ESUsersRealm.TYPE);
|
||||||
|
builder.put("shield.authc.realms.realm_1.order", 0);
|
||||||
|
builder.put("shield.authc.realms.realm_2.type", ESUsersRealm.TYPE);
|
||||||
|
builder.put("shield.authc.realms.realm_2.order", 1);
|
||||||
|
new Realms(builder.build(), factories);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithEmptySettings() throws Exception {
|
||||||
|
Realms realms = new Realms(ImmutableSettings.EMPTY, factories);
|
||||||
|
Iterator<Realm> iter = realms.iterator();
|
||||||
|
assertThat(iter.hasNext(), is(true));
|
||||||
|
Realm realm = iter.next();
|
||||||
|
assertThat(realm, notNullValue());
|
||||||
|
assertThat(realm.type(), equalTo(ESUsersRealm.TYPE));
|
||||||
|
assertThat(realm.name(), equalTo("default_" + ESUsersRealm.TYPE));
|
||||||
|
assertThat(iter.hasNext(), is(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DummyRealm extends Realm {
|
||||||
|
|
||||||
|
public DummyRealm(String type, String name, Settings settings) {
|
||||||
|
super(type, name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(AuthenticationToken token) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationToken token(RestRequest request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthenticationToken token(TransportMessage message) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User authenticate(AuthenticationToken token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Factory extends Realm.Factory<DummyRealm> {
|
||||||
|
|
||||||
|
public Factory(String type, boolean internal) {
|
||||||
|
super(type, internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DummyRealm create(String name, Settings settings) {
|
||||||
|
return new DummyRealm(type(), name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DummyRealm createDefault(String name) {
|
||||||
|
return type().equals("esusers") ? new DummyRealm("esusers", name, ImmutableSettings.EMPTY) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,14 +5,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc.active_directory;
|
package org.elasticsearch.shield.authc.active_directory;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.util.Providers;
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.authc.ldap.*;
|
import org.elasticsearch.shield.authc.ldap.LdapConnection;
|
||||||
|
import org.elasticsearch.shield.authc.ldap.LdapConnectionFactory;
|
||||||
|
import org.elasticsearch.shield.authc.ldap.LdapConnectionTests;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||||
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapConnection;
|
import org.elasticsearch.shield.authc.support.ldap.AbstractLdapConnection;
|
||||||
import org.elasticsearch.shield.ssl.SSLService;
|
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapTest;
|
import org.elasticsearch.shield.authc.support.ldap.LdapTest;
|
||||||
|
import org.elasticsearch.shield.ssl.SSLService;
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
import org.elasticsearch.test.junit.annotations.Network;
|
import org.elasticsearch.test.junit.annotations.Network;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
@ -28,18 +31,18 @@ import static org.hamcrest.Matchers.*;
|
|||||||
|
|
||||||
@Network
|
@Network
|
||||||
public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
public static final String AD_LDAP_URL = "ldaps://54.213.145.20:636";
|
public static final String AD_LDAP_URL = "ldaps://54.213.145.20:636";
|
||||||
public static final String PASSWORD = "NickFuryHeartsES";
|
public static final String PASSWORD = "NickFuryHeartsES";
|
||||||
public static final String AD_DOMAIN = "ad.test.elasticsearch.com";
|
public static final String AD_DOMAIN = "ad.test.elasticsearch.com";
|
||||||
public static String SETTINGS_PREFIX = ActiveDirectoryRealm.class.getPackage().getName().substring("com.elasticsearch.".length()) + '.';
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setTrustStore() throws URISyntaxException {
|
public static void setTrustStore() throws URISyntaxException {
|
||||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
LdapSslSocketFactory.init(Providers.of(new SSLService(ImmutableSettings.builder()
|
||||||
.put("shield.ssl.keystore.path", filename)
|
.put("shield.ssl.keystore.path", filename)
|
||||||
.put("shield.ssl.keystore.password", "changeit")
|
.put("shield.ssl.keystore.password", "changeit")
|
||||||
.build()));
|
.build())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@ -47,7 +50,7 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
LdapSslSocketFactory.clear();
|
LdapSslSocketFactory.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @SuppressWarnings("unchecked")
|
||||||
public void testAdAuth() {
|
public void testAdAuth() {
|
||||||
ActiveDirectoryConnectionFactory connectionFactory = new ActiveDirectoryConnectionFactory(
|
ActiveDirectoryConnectionFactory connectionFactory = new ActiveDirectoryConnectionFactory(
|
||||||
buildAdSettings(AD_LDAP_URL, AD_DOMAIN));
|
buildAdSettings(AD_LDAP_URL, AD_DOMAIN));
|
||||||
@ -64,8 +67,7 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
containsString("SHIELD"),
|
containsString("SHIELD"),
|
||||||
containsString("Users"),
|
containsString("Users"),
|
||||||
containsString("Domain Users"),
|
containsString("Domain Users"),
|
||||||
containsString("Supers")
|
containsString("Supers")));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,11 +84,10 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @SuppressWarnings("unchecked")
|
||||||
public void testAdAuth_specificUserSearch() {
|
public void testAdAuth_specificUserSearch() {
|
||||||
ActiveDirectoryConnectionFactory connectionFactory = new ActiveDirectoryConnectionFactory(
|
Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com");
|
||||||
buildAdSettings(AD_LDAP_URL, AD_DOMAIN,
|
ActiveDirectoryConnectionFactory connectionFactory = new ActiveDirectoryConnectionFactory(settings);
|
||||||
"CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com"));
|
|
||||||
|
|
||||||
String userName = "hulk";
|
String userName = "hulk";
|
||||||
try (AbstractLdapConnection ldap = connectionFactory.open(userName, SecuredStringTests.build(PASSWORD))) {
|
try (AbstractLdapConnection ldap = connectionFactory.open(userName, SecuredStringTests.build(PASSWORD))) {
|
||||||
@ -99,18 +100,16 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
containsString("Philanthropists"),
|
containsString("Philanthropists"),
|
||||||
//containsString("Users"), Users group is in a different user context
|
//containsString("Users"), Users group is in a different user context
|
||||||
containsString("Domain Users"),
|
containsString("Domain Users"),
|
||||||
containsString("Supers")
|
containsString("Supers")));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test @SuppressWarnings("unchecked")
|
||||||
public void testAD_standardLdapConnection(){
|
public void testAD_standardLdapConnection(){
|
||||||
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
|
String groupSearchBase = "DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||||
String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
String userTemplate = "CN={0},CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com";
|
||||||
boolean isSubTreeSearch = true;
|
Settings settings = LdapTest.buildLdapSettings(AD_LDAP_URL, userTemplate, groupSearchBase, true);
|
||||||
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(
|
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(settings);
|
||||||
LdapTest.buildLdapSettings(AD_LDAP_URL, userTemplate, groupSearchBase, isSubTreeSearch));
|
|
||||||
|
|
||||||
String user = "Bruce Banner";
|
String user = "Bruce Banner";
|
||||||
try (LdapConnection ldap = connectionFactory.open(user, SecuredStringTests.build(PASSWORD))) {
|
try (LdapConnection ldap = connectionFactory.open(user, SecuredStringTests.build(PASSWORD))) {
|
||||||
@ -122,6 +121,7 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
containsString("SHIELD"),
|
containsString("SHIELD"),
|
||||||
containsString("Geniuses"),
|
containsString("Geniuses"),
|
||||||
containsString("Philanthropists")));
|
containsString("Philanthropists")));
|
||||||
|
|
||||||
assertThat(groups2, containsInAnyOrder(
|
assertThat(groups2, containsInAnyOrder(
|
||||||
containsString("Avengers"),
|
containsString("Avengers"),
|
||||||
containsString("SHIELD"),
|
containsString("SHIELD"),
|
||||||
@ -132,16 +132,16 @@ public class ActiveDirectoryFactoryTests extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
public static Settings buildAdSettings(String ldapUrl, String adDomainName) {
|
public static Settings buildAdSettings(String ldapUrl, String adDomainName) {
|
||||||
return ImmutableSettings.builder()
|
return ImmutableSettings.builder()
|
||||||
.put(SETTINGS_PREFIX + ActiveDirectoryConnectionFactory.URLS_SETTING, ldapUrl)
|
.put(ActiveDirectoryConnectionFactory.URLS_SETTING, ldapUrl)
|
||||||
.put(SETTINGS_PREFIX + ActiveDirectoryConnectionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
.put(ActiveDirectoryConnectionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN) {
|
public static Settings buildAdSettings(String ldapUrl, String adDomainName, String userSearchDN) {
|
||||||
return ImmutableSettings.builder()
|
return ImmutableSettings.builder()
|
||||||
.putArray(SETTINGS_PREFIX + ActiveDirectoryConnectionFactory.URLS_SETTING, ldapUrl)
|
.putArray(ActiveDirectoryConnectionFactory.URLS_SETTING, ldapUrl)
|
||||||
.put(SETTINGS_PREFIX + ActiveDirectoryConnectionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
.put(ActiveDirectoryConnectionFactory.AD_DOMAIN_NAME_SETTING, adDomainName)
|
||||||
.put(SETTINGS_PREFIX + ActiveDirectoryConnectionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN)
|
.put(ActiveDirectoryConnectionFactory.AD_USER_SEARCH_BASEDN_SETTING, userSearchDN)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.active_directory;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Guice;
|
|
||||||
import org.elasticsearch.common.inject.Injector;
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
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.ssl.SSLService;
|
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ActiveDirectoryModuleTests extends ElasticsearchTestCase {
|
|
||||||
|
|
||||||
private ThreadPool threadPool;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init() throws Exception {
|
|
||||||
threadPool = new ThreadPool("test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void shutdown() {
|
|
||||||
threadPool.shutdownNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnabled() throws Exception {
|
|
||||||
assertThat(ActiveDirectoryModule.enabled(ImmutableSettings.EMPTY), is(false));
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc", false)
|
|
||||||
.build();
|
|
||||||
assertThat(ActiveDirectoryModule.enabled(settings), is(false));
|
|
||||||
settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.active_directory.enabled", false)
|
|
||||||
.build();
|
|
||||||
assertThat(ActiveDirectoryModule.enabled(settings), is(false));
|
|
||||||
settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.active_directory.enabled", true)
|
|
||||||
.build();
|
|
||||||
assertThat(ActiveDirectoryModule.enabled(settings), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() throws Exception {
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("client.type", "node")
|
|
||||||
.put("shield.authc.active_directory.url", "ldap://example.com:389")
|
|
||||||
.put("shield.authc.active_directory.domain_name", "example.com")
|
|
||||||
.build();
|
|
||||||
Injector injector = Guice.createInjector(new TestModule(settings), new ActiveDirectoryModule(settings));
|
|
||||||
ActiveDirectoryRealm realm = injector.getInstance(ActiveDirectoryRealm.class);
|
|
||||||
assertThat(realm, notNullValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestModule extends AbstractModule {
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
public TestModule(Settings settings) {
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
Environment env = new Environment(settings);
|
|
||||||
bind(Settings.class).toInstance(settings);
|
|
||||||
bind(Environment.class).toInstance(env);
|
|
||||||
bind(ThreadPool.class).toInstance(threadPool);
|
|
||||||
bind(ResourceWatcherService.class).asEagerSingleton();
|
|
||||||
bind(RestController.class).toInstance(mock(RestController.class));
|
|
||||||
bind(SSLService.class).toProvider(Providers.<SSLService>of(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.esusers;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Guice;
|
|
||||||
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;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ESUsersModuleTests extends ElasticsearchTestCase {
|
|
||||||
|
|
||||||
private Path users;
|
|
||||||
private Path usersRoles;
|
|
||||||
private ThreadPool threadPool;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init() throws Exception {
|
|
||||||
users = Paths.get(getClass().getResource("users").toURI());
|
|
||||||
usersRoles = Paths.get(getClass().getResource("users_roles").toURI());
|
|
||||||
threadPool = new ThreadPool("test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void shutdown() {
|
|
||||||
threadPool.shutdownNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() throws Exception {
|
|
||||||
Settings settings = ImmutableSettings.builder().put("client.type", "node").build();
|
|
||||||
Injector injector = Guice.createInjector(new TestModule(users, usersRoles, threadPool), new ESUsersModule(settings));
|
|
||||||
ESUsersRealm realm = injector.getInstance(ESUsersRealm.class);
|
|
||||||
assertThat(realm, notNullValue());
|
|
||||||
assertThat(realm.userPasswdStore, notNullValue());
|
|
||||||
assertThat(realm.userPasswdStore, instanceOf(FileUserPasswdStore.class));
|
|
||||||
assertThat(realm.userRolesStore, notNullValue());
|
|
||||||
assertThat(realm.userRolesStore, instanceOf(FileUserRolesStore.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnabled() throws Exception {
|
|
||||||
assertThat(ESUsersModule.enabled(ImmutableSettings.EMPTY), is(true));
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.esusers.enabled", false)
|
|
||||||
.build();
|
|
||||||
assertThat(ESUsersModule.enabled(settings), is(false));
|
|
||||||
settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.esusers.enabled", true)
|
|
||||||
.build();
|
|
||||||
assertThat(ESUsersModule.enabled(settings), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestModule extends AbstractModule {
|
|
||||||
|
|
||||||
final Path users;
|
|
||||||
final Path usersRoles;
|
|
||||||
private ThreadPool threadPool;
|
|
||||||
|
|
||||||
public TestModule(Path users, Path usersRoles, ThreadPool threadPool) {
|
|
||||||
this.users = users;
|
|
||||||
this.usersRoles = usersRoles;
|
|
||||||
this.threadPool = threadPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.esusers.file.users", users.toAbsolutePath())
|
|
||||||
.put("shield.authc.esusers.file.users_roles", usersRoles.toAbsolutePath())
|
|
||||||
.build();
|
|
||||||
Environment env = new Environment(settings);
|
|
||||||
bind(Settings.class).toInstance(settings);
|
|
||||||
bind(Environment.class).toInstance(env);
|
|
||||||
bind(ThreadPool.class).toInstance(threadPool);
|
|
||||||
bind(ResourceWatcherService.class).asEagerSingleton();
|
|
||||||
bind(RestController.class).toInstance(mock(RestController.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -60,16 +60,15 @@ public class ESUsersRealmTests extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRestHeaderRegistration() {
|
public void testRestHeaderRegistration() {
|
||||||
new ESUsersRealm(ImmutableSettings.EMPTY, mock(FileUserPasswdStore.class), mock(FileUserRolesStore.class), restController);
|
new ESUsersRealm.Factory(mock(Environment.class), mock(ResourceWatcherService.class), restController);
|
||||||
verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAuthenticate() throws Exception {
|
public void testAuthenticate() throws Exception {
|
||||||
Settings settings = ImmutableSettings.builder().build();
|
|
||||||
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
||||||
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
||||||
ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore, restController);
|
ESUsersRealm realm = new ESUsersRealm("esusers-test", ImmutableSettings.EMPTY, userPasswdStore, userRolesStore);
|
||||||
User user = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
User user = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
assertThat(user, notNullValue());
|
assertThat(user, notNullValue());
|
||||||
assertThat(user.principal(), equalTo("user1"));
|
assertThat(user.principal(), equalTo("user1"));
|
||||||
@ -81,11 +80,11 @@ public class ESUsersRealmTests extends ElasticsearchTestCase {
|
|||||||
@Test @Repeat(iterations = 20)
|
@Test @Repeat(iterations = 20)
|
||||||
public void testAuthenticate_Caching() throws Exception {
|
public void testAuthenticate_Caching() throws Exception {
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.cache.hash_algo", Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT))
|
.put("cache.hash_algo", Hasher.values()[randomIntBetween(0, Hasher.values().length - 1)].name().toLowerCase(Locale.ROOT))
|
||||||
.build();
|
.build();
|
||||||
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
||||||
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
||||||
ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore, restController);
|
ESUsersRealm realm = new ESUsersRealm("esusers-test", settings, userPasswdStore, userRolesStore);
|
||||||
User user1 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
User user1 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
User user2 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
User user2 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
assertThat(user1, sameInstance(user2));
|
assertThat(user1, sameInstance(user2));
|
||||||
@ -96,7 +95,7 @@ public class ESUsersRealmTests extends ElasticsearchTestCase {
|
|||||||
userRolesStore = spy(new UserRolesStore());
|
userRolesStore = spy(new UserRolesStore());
|
||||||
doReturn(true).when(userPasswdStore).verifyPassword("user1", SecuredStringTests.build("test123"));
|
doReturn(true).when(userPasswdStore).verifyPassword("user1", SecuredStringTests.build("test123"));
|
||||||
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
|
doReturn(new String[] { "role1", "role2" }).when(userRolesStore).roles("user1");
|
||||||
ESUsersRealm realm = new ESUsersRealm(ImmutableSettings.EMPTY, userPasswdStore, userRolesStore, restController);
|
ESUsersRealm realm = new ESUsersRealm("esusers-test", ImmutableSettings.EMPTY, userPasswdStore, userRolesStore);
|
||||||
User user1 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
User user1 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
User user2 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
User user2 = realm.authenticate(new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
assertThat(user1, sameInstance(user2));
|
assertThat(user1, sameInstance(user2));
|
||||||
@ -114,10 +113,9 @@ public class ESUsersRealmTests extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToken() throws Exception {
|
public void testToken() throws Exception {
|
||||||
Settings settings = ImmutableSettings.builder().build();
|
|
||||||
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
when(userPasswdStore.verifyPassword("user1", SecuredStringTests.build("test123"))).thenReturn(true);
|
||||||
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
when(userRolesStore.roles("user1")).thenReturn(new String[] { "role1", "role2" });
|
||||||
ESUsersRealm realm = new ESUsersRealm(settings, userPasswdStore, userRolesStore, restController);
|
ESUsersRealm realm = new ESUsersRealm("esusers-test", ImmutableSettings.EMPTY, userPasswdStore, userRolesStore);
|
||||||
|
|
||||||
TransportRequest request = new TransportRequest() {};
|
TransportRequest request = new TransportRequest() {};
|
||||||
UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
UsernamePasswordToken.putTokenHeader(request, new UsernamePasswordToken("user1", SecuredStringTests.build("test123")));
|
||||||
@ -132,7 +130,7 @@ public class ESUsersRealmTests extends ElasticsearchTestCase {
|
|||||||
@Test @SuppressWarnings("unchecked")
|
@Test @SuppressWarnings("unchecked")
|
||||||
public void testRestHeadersAreCopied() throws Exception {
|
public void testRestHeadersAreCopied() throws Exception {
|
||||||
// the required header will be registered only if ESUsersRealm is actually used.
|
// the required header will be registered only if ESUsersRealm is actually used.
|
||||||
new ESUsersRealm(ImmutableSettings.EMPTY, new UserPasswdStore(), new UserRolesStore(), restController);
|
new ESUsersRealm("esusers-test", ImmutableSettings.EMPTY, new UserPasswdStore(), new UserRolesStore());
|
||||||
when(restController.relevantHeaders()).thenReturn(ImmutableSet.of(UsernamePasswordToken.BASIC_AUTH_HEADER));
|
when(restController.relevantHeaders()).thenReturn(ImmutableSet.of(UsernamePasswordToken.BASIC_AUTH_HEADER));
|
||||||
when(client.admin()).thenReturn(adminClient);
|
when(client.admin()).thenReturn(adminClient);
|
||||||
when(adminClient.cluster()).thenReturn(mock(ClusterAdminClient.class));
|
when(adminClient.cluster()).thenReturn(mock(ClusterAdminClient.class));
|
||||||
|
@ -69,14 +69,18 @@ public class FileUserPasswdStoreTests extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("watcher.interval.high", "2s")
|
.put("watcher.interval.high", "2s")
|
||||||
.put("shield.authc.esusers.files.users", tmp.toAbsolutePath())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Settings esusersSettings = ImmutableSettings.builder()
|
||||||
|
.put("files.users", tmp.toAbsolutePath())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
Environment env = new Environment(settings);
|
Environment env = new Environment(settings);
|
||||||
threadPool = new ThreadPool("test");
|
threadPool = new ThreadPool("test");
|
||||||
watcherService = new ResourceWatcherService(settings, threadPool);
|
watcherService = new ResourceWatcherService(settings, threadPool);
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
FileUserPasswdStore store = new FileUserPasswdStore(settings, env, watcherService, new RefreshListener() {
|
FileUserPasswdStore store = new FileUserPasswdStore(esusersSettings, env, watcherService, new RefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
|
@ -62,14 +62,17 @@ public class FileUserRolesStoreTests extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("watcher.interval.high", "2s")
|
.put("watcher.interval.high", "2s")
|
||||||
.put("shield.authc.esusers.files.users_roles", tmp.toAbsolutePath())
|
.build();
|
||||||
|
|
||||||
|
Settings esusersSettings = ImmutableSettings.builder()
|
||||||
|
.put("files.users_roles", tmp.toAbsolutePath())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Environment env = new Environment(settings);
|
Environment env = new Environment(settings);
|
||||||
threadPool = new ThreadPool("test");
|
threadPool = new ThreadPool("test");
|
||||||
watcherService = new ResourceWatcherService(settings, threadPool);
|
watcherService = new ResourceWatcherService(settings, threadPool);
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
FileUserRolesStore store = new FileUserRolesStore(settings, env, watcherService, new RefreshListener() {
|
FileUserRolesStore store = new FileUserRolesStore(esusersSettings, env, watcherService, new RefreshListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onRefresh() {
|
public void onRefresh() {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
@ -114,13 +117,18 @@ public class FileUserRolesStoreTests extends ElasticsearchTestCase {
|
|||||||
try {
|
try {
|
||||||
threadPool = new ThreadPool("test");
|
threadPool = new ThreadPool("test");
|
||||||
File usersRoles = writeUsersRoles("role1:admin");
|
File usersRoles = writeUsersRoles("role1:admin");
|
||||||
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("watcher.enabled", "false")
|
.put("watcher.enabled", "false")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoles.toPath().toAbsolutePath())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Settings esusersSettings = ImmutableSettings.builder()
|
||||||
|
.put("files.users_roles", usersRoles.toPath().toAbsolutePath())
|
||||||
|
.build();
|
||||||
|
|
||||||
Environment env = new Environment(settings);
|
Environment env = new Environment(settings);
|
||||||
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
|
ResourceWatcherService watcherService = new ResourceWatcherService(settings, threadPool);
|
||||||
FileUserRolesStore store = new FileUserRolesStore(settings, env, watcherService);
|
FileUserRolesStore store = new FileUserRolesStore(esusersSettings, env, watcherService);
|
||||||
assertThat(store.roles("user"), equalTo(Strings.EMPTY_ARRAY));
|
assertThat(store.roles("user"), equalTo(Strings.EMPTY_ARRAY));
|
||||||
} finally {
|
} finally {
|
||||||
if (threadPool != null) {
|
if (threadPool != null) {
|
||||||
|
@ -76,8 +76,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = new File(tmpFolder, "users");
|
File userFile = new File(tmpFolder, "users");
|
||||||
File userRolesFile = new File(tmpFolder, "users_roles");
|
File userRolesFile = new File(tmpFolder, "users_roles");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
||||||
@ -106,8 +107,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = writeFile("user2:hash2");
|
File userFile = writeFile("user2:hash2");
|
||||||
File userRolesFile = writeFile("r3:user2\nr4:user2");
|
File userRolesFile = writeFile("r3:user2\nr4:user2");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
||||||
@ -141,8 +143,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = writeFile("user2:hash2");
|
File userFile = writeFile("user2:hash2");
|
||||||
File userRolesFile = writeFile("r3:user2\nr4:user2");
|
File userRolesFile = writeFile("r3:user2\nr4:user2");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"));
|
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"));
|
||||||
@ -161,8 +164,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = writeFile("user1:hash1");
|
File userFile = writeFile("user1:hash1");
|
||||||
File userRolesFile = newTempFile();
|
File userRolesFile = newTempFile();
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
ESUsersTool.Useradd cmd = new ESUsersTool.Useradd(new MockTerminal(), "user1", SecuredStringTests.build("changeme"), "r1", "r2");
|
||||||
@ -194,8 +198,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = writeFile("user1:hash2");
|
File userFile = writeFile("user1:hash2");
|
||||||
File userRolesFile = writeFile("r3:user1\nr4:user1");
|
File userRolesFile = writeFile("r3:user1\nr4:user1");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Userdel cmd = new ESUsersTool.Userdel(new MockTerminal(), "user1");
|
ESUsersTool.Userdel cmd = new ESUsersTool.Userdel(new MockTerminal(), "user1");
|
||||||
@ -217,8 +222,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = writeFile("user1:hash2");
|
File userFile = writeFile("user1:hash2");
|
||||||
File userRolesFile = writeFile("r3:user1\nr4:user1");
|
File userRolesFile = writeFile("r3:user1\nr4:user1");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
CaptureOutputTerminal terminal = new CaptureOutputTerminal();
|
CaptureOutputTerminal terminal = new CaptureOutputTerminal();
|
||||||
|
|
||||||
@ -246,8 +252,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File userFile = new File(dir, "users");
|
File userFile = new File(dir, "users");
|
||||||
File userRolesFile = new File(dir, "users_roles");
|
File userRolesFile = new File(dir, "users_roles");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", userRolesFile)
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", userRolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Userdel cmd = new ESUsersTool.Userdel(new MockTerminal(), "user2");
|
ESUsersTool.Userdel cmd = new ESUsersTool.Userdel(new MockTerminal(), "user2");
|
||||||
@ -301,7 +308,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
public void testPasswd_Cmd() throws Exception {
|
public void testPasswd_Cmd() throws Exception {
|
||||||
File userFile = writeFile("user1:hash2");
|
File userFile = writeFile("user1:hash2");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user1", "changeme".toCharArray());
|
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user1", "changeme".toCharArray());
|
||||||
@ -322,7 +330,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
public void testPasswd_Cmd_UnknownUser() throws Exception {
|
public void testPasswd_Cmd_UnknownUser() throws Exception {
|
||||||
File userFile = writeFile("user1:hash2");
|
File userFile = writeFile("user1:hash2");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user2", "changeme".toCharArray());
|
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user2", "changeme".toCharArray());
|
||||||
@ -334,7 +343,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
public void testPasswd_Cmd_MissingFiles() throws Exception {
|
public void testPasswd_Cmd_MissingFiles() throws Exception {
|
||||||
File userFile = newTempFile();
|
File userFile = newTempFile();
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", userFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users", userFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user2", "changeme".toCharArray());
|
ESUsersTool.Passwd cmd = new ESUsersTool.Passwd(new MockTerminal(), "user2", "changeme".toCharArray());
|
||||||
@ -359,8 +369,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash");
|
File usersFile = writeFile("admin:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\n");
|
File usersRoleFile = writeFile("admin: admin\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// invalid role names
|
// invalid role names
|
||||||
@ -383,8 +394,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash\nuser:hash");
|
File usersFile = writeFile("admin:hash\nuser:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", new String[]{"foo"}, Strings.EMPTY_ARRAY);
|
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", new String[]{"foo"}, Strings.EMPTY_ARRAY);
|
||||||
@ -404,8 +416,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash\nuser:hash");
|
File usersFile = writeFile("admin:hash\nuser:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo: user\nbar: user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo: user\nbar: user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", Strings.EMPTY_ARRAY, new String[]{"foo"});
|
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", Strings.EMPTY_ARRAY, new String[]{"foo"});
|
||||||
@ -425,8 +438,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash\nuser:hash");
|
File usersFile = writeFile("admin:hash\nuser:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", new String[]{"newrole"}, new String[]{"foo"});
|
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", new String[]{"newrole"}, new String[]{"foo"});
|
||||||
@ -446,8 +460,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash\nuser:hash");
|
File usersFile = writeFile("admin:hash\nuser:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", Strings.EMPTY_ARRAY, new String[]{"user", "foo", "bar"});
|
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "user", Strings.EMPTY_ARRAY, new String[]{"user", "foo", "bar"});
|
||||||
@ -464,8 +479,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:hash\nuser:hash");
|
File usersFile = writeFile("admin:hash\nuser:hash");
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "does-not-exist", Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY);
|
ESUsersTool.Roles cmd = new ESUsersTool.Roles(new MockTerminal(), "does-not-exist", Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY);
|
||||||
@ -480,8 +496,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser:user\nfoo:user\nbar:user\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -499,8 +516,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("admin: admin\n");
|
File usersRoleFile = writeFile("admin: admin\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nmyrole:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nmyrole:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -529,7 +547,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -548,7 +567,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -568,8 +588,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:{plain}changeme\nuser:{plain}changeme\nno-roles-user:{plain}changeme\n");
|
File usersFile = writeFile("admin:{plain}changeme\nuser:{plain}changeme\nno-roles-user:{plain}changeme\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -587,7 +608,8 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
public void testListUsersAndRoles_Cmd_listSingleUserNotFound() throws Exception {
|
public void testListUsersAndRoles_Cmd_listSingleUserNotFound() throws Exception {
|
||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal();
|
CaptureOutputTerminal catchTerminalOutput = new CaptureOutputTerminal();
|
||||||
@ -603,8 +625,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
File usersRoleFile = writeFile("admin: admin\nuser: user\nfoo:user\nbar:user\n");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -625,8 +648,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersRoleFile = writeFile("");
|
File usersRoleFile = writeFile("");
|
||||||
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
File rolesFile = writeFile("admin:\n cluster: all\n\nuser:\n cluster: all\n\nfoo:\n cluster: all\n\nbar:\n cluster: all");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
.put("shield.authz.store.files.roles", rolesFile)
|
.put("shield.authz.store.files.roles", rolesFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@ -646,8 +670,9 @@ public class ESUsersToolTests extends CliToolTestCase {
|
|||||||
File usersFile = writeFile("admin:{plain}changeme");
|
File usersFile = writeFile("admin:{plain}changeme");
|
||||||
File usersRoleFile = writeFile("");
|
File usersRoleFile = writeFile("");
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.esusers.files.users_roles", usersRoleFile)
|
.put("shield.authc.realms.esusers.type", "esusers")
|
||||||
.put("shield.authc.esusers.files.users", usersFile)
|
.put("shield.authc.realms.esusers.files.users_roles", usersRoleFile)
|
||||||
|
.put("shield.authc.realms.esusers.files.users", usersFile)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
CaptureOutputTerminal loggingTerminal = new CaptureOutputTerminal();
|
CaptureOutputTerminal loggingTerminal = new CaptureOutputTerminal();
|
||||||
|
@ -19,23 +19,21 @@ public class LdapConnectionTests extends LdapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBindWithTemplates() {
|
public void testBindWithTemplates() {
|
||||||
String[] ldapUrls = new String[]{ldapUrl()};
|
String[] ldapUrls = new String[] { ldapUrl() };
|
||||||
String groupSearchBase = "o=sevenSeas";
|
String groupSearchBase = "o=sevenSeas";
|
||||||
boolean isSubTreeSearch = true;
|
String[] userTemplates = new String[] {
|
||||||
String[] userTemplates = new String[]{
|
|
||||||
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
|
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
|
||||||
"wrongname={0},ou=people,o=sevenSeas",
|
"wrongname={0},ou=people,o=sevenSeas",
|
||||||
"cn={0},ou=people,o=sevenSeas", //this last one should work
|
"cn={0},ou=people,o=sevenSeas", //this last one should work
|
||||||
};
|
};
|
||||||
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(
|
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(
|
||||||
buildLdapSettings(ldapUrls, userTemplates, groupSearchBase, isSubTreeSearch));
|
buildLdapSettings(ldapUrls, userTemplates, groupSearchBase, true));
|
||||||
|
|
||||||
String user = "Horatio Hornblower";
|
String user = "Horatio Hornblower";
|
||||||
SecuredString userPass = SecuredStringTests.build("pass");
|
SecuredString userPass = SecuredStringTests.build("pass");
|
||||||
|
|
||||||
try (LdapConnection ldap = connectionFactory.open(user, userPass)) {
|
try (LdapConnection ldap = connectionFactory.open(user, userPass)) {
|
||||||
String dn = ldap.authenticatedUserDn();
|
String dn = ldap.authenticatedUserDn();
|
||||||
|
|
||||||
assertThat(dn, containsString(user));
|
assertThat(dn, containsString(user));
|
||||||
//assertThat( attrs.get("uid"), arrayContaining("hhornblo"));
|
//assertThat( attrs.get("uid"), arrayContaining("hhornblo"));
|
||||||
}
|
}
|
||||||
@ -43,10 +41,10 @@ public class LdapConnectionTests extends LdapTest {
|
|||||||
|
|
||||||
@Test(expected = LdapException.class)
|
@Test(expected = LdapException.class)
|
||||||
public void testBindWithBogusTemplates() {
|
public void testBindWithBogusTemplates() {
|
||||||
String[] ldapUrl = new String[]{ldapUrl()};
|
String[] ldapUrl = new String[] { ldapUrl() };
|
||||||
String groupSearchBase = "o=sevenSeas";
|
String groupSearchBase = "o=sevenSeas";
|
||||||
boolean isSubTreeSearch = true;
|
boolean isSubTreeSearch = true;
|
||||||
String[] userTemplates = new String[]{
|
String[] userTemplates = new String[] {
|
||||||
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
|
"cn={0},ou=something,ou=obviously,ou=incorrect,o=sevenSeas",
|
||||||
"wrongname={0},ou=people,o=sevenSeas",
|
"wrongname={0},ou=people,o=sevenSeas",
|
||||||
"asdf={0},ou=people,o=sevenSeas", //none of these should work
|
"asdf={0},ou=people,o=sevenSeas", //none of these should work
|
||||||
@ -65,9 +63,8 @@ public class LdapConnectionTests extends LdapTest {
|
|||||||
String groupSearchBase = "o=sevenSeas";
|
String groupSearchBase = "o=sevenSeas";
|
||||||
String userTemplate = "cn={0},ou=people,o=sevenSeas";
|
String userTemplate = "cn={0},ou=people,o=sevenSeas";
|
||||||
|
|
||||||
boolean isSubTreeSearch = true;
|
|
||||||
LdapConnectionFactory ldapFac = new LdapConnectionFactory(
|
LdapConnectionFactory ldapFac = new LdapConnectionFactory(
|
||||||
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, true));
|
||||||
|
|
||||||
String user = "Horatio Hornblower";
|
String user = "Horatio Hornblower";
|
||||||
SecuredString userPass = SecuredStringTests.build("pass");
|
SecuredString userPass = SecuredStringTests.build("pass");
|
||||||
@ -82,9 +79,8 @@ public class LdapConnectionTests extends LdapTest {
|
|||||||
public void testGroupLookup_OneLevel() {
|
public void testGroupLookup_OneLevel() {
|
||||||
String groupSearchBase = "ou=crews,ou=groups,o=sevenSeas";
|
String groupSearchBase = "ou=crews,ou=groups,o=sevenSeas";
|
||||||
String userTemplate = "cn={0},ou=people,o=sevenSeas";
|
String userTemplate = "cn={0},ou=people,o=sevenSeas";
|
||||||
boolean isSubTreeSearch = false;
|
|
||||||
LdapConnectionFactory ldapFac = new LdapConnectionFactory(
|
LdapConnectionFactory ldapFac = new LdapConnectionFactory(
|
||||||
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, false));
|
||||||
|
|
||||||
String user = "Horatio Hornblower";
|
String user = "Horatio Hornblower";
|
||||||
try (LdapConnection ldap = ldapFac.open(user, SecuredStringTests.build("pass"))) {
|
try (LdapConnection ldap = ldapFac.open(user, SecuredStringTests.build("pass"))) {
|
||||||
|
@ -55,7 +55,7 @@ public class LdapGroupToRoleMapperTest extends ElasticsearchTestCase {
|
|||||||
public void testYaml() throws IOException {
|
public void testYaml() throws IOException {
|
||||||
File file = this.getResource("../support/ldap/role_mapping.yml");
|
File file = this.getResource("../support/ldap/role_mapping.yml");
|
||||||
Settings settings = ImmutableSettings.settingsBuilder()
|
Settings settings = ImmutableSettings.settingsBuilder()
|
||||||
.put("shield.authc.ldap." + LdapGroupToRoleMapper.ROLE_MAPPING_FILE_SETTING, file.getCanonicalPath())
|
.put(LdapGroupToRoleMapper.ROLE_MAPPING_FILE_SETTING, file.getCanonicalPath())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
AbstractGroupToRoleMapper mapper = new LdapGroupToRoleMapper(settings,
|
AbstractGroupToRoleMapper mapper = new LdapGroupToRoleMapper(settings,
|
||||||
@ -71,7 +71,7 @@ public class LdapGroupToRoleMapperTest extends ElasticsearchTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testRelativeDN() {
|
public void testRelativeDN() {
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.ldap." + AbstractGroupToRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, true)
|
.put(AbstractGroupToRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
AbstractGroupToRoleMapper mapper = new LdapGroupToRoleMapper(settings,
|
AbstractGroupToRoleMapper mapper = new LdapGroupToRoleMapper(settings,
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
package org.elasticsearch.shield.authc.ldap;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.Guice;
|
|
||||||
import org.elasticsearch.common.inject.Injector;
|
|
||||||
import org.elasticsearch.common.inject.util.Providers;
|
|
||||||
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.ssl.SSLService;
|
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class LdapModuleTests extends ElasticsearchTestCase {
|
|
||||||
|
|
||||||
private ThreadPool threadPool;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init() throws Exception {
|
|
||||||
threadPool = new ThreadPool("test");
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void shutdown() {
|
|
||||||
threadPool.shutdownNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnabled() throws Exception {
|
|
||||||
assertThat(LdapModule.enabled(ImmutableSettings.EMPTY), is(false));
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc", false)
|
|
||||||
.build();
|
|
||||||
assertThat(LdapModule.enabled(settings), is(false));
|
|
||||||
settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.ldap.enabled", false)
|
|
||||||
.build();
|
|
||||||
assertThat(LdapModule.enabled(settings), is(false));
|
|
||||||
settings = ImmutableSettings.builder()
|
|
||||||
.put("shield.authc.ldap.enabled", true)
|
|
||||||
.build();
|
|
||||||
assertThat(LdapModule.enabled(settings), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() throws Exception {
|
|
||||||
Settings settings = ImmutableSettings.builder()
|
|
||||||
.put("client.type", "node")
|
|
||||||
.put("shield.authc.ldap.url", "ldap://example.com:389")
|
|
||||||
.build();
|
|
||||||
Injector injector = Guice.createInjector(new TestModule(settings), new LdapModule(settings));
|
|
||||||
LdapRealm realm = injector.getInstance(LdapRealm.class);
|
|
||||||
assertThat(realm, notNullValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestModule extends AbstractModule {
|
|
||||||
private final Settings settings;
|
|
||||||
|
|
||||||
public TestModule(Settings settings) {
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure() {
|
|
||||||
Environment env = new Environment(settings);
|
|
||||||
bind(Settings.class).toInstance(settings);
|
|
||||||
bind(Environment.class).toInstance(env);
|
|
||||||
bind(ThreadPool.class).toInstance(threadPool);
|
|
||||||
bind(ResourceWatcherService.class).asEagerSingleton();
|
|
||||||
bind(RestController.class).toInstance(mock(RestController.class));
|
|
||||||
bind(SSLService.class).toProvider(Providers.<SSLService>of(null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.shield.authc.ldap;
|
|||||||
|
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.shield.User;
|
import org.elasticsearch.shield.User;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||||
@ -26,6 +27,7 @@ import static org.mockito.Matchers.anyString;
|
|||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
public class LdapRealmTest extends LdapTest {
|
public class LdapRealmTest extends LdapTest {
|
||||||
|
|
||||||
public static final String VALID_USER_TEMPLATE = "cn={0},ou=people,o=sevenSeas";
|
public static final String VALID_USER_TEMPLATE = "cn={0},ou=people,o=sevenSeas";
|
||||||
public static final String VALID_USERNAME = "Thomas Masterman Hardy";
|
public static final String VALID_USERNAME = "Thomas Masterman Hardy";
|
||||||
public static final String PASSWORD = "pass";
|
public static final String PASSWORD = "pass";
|
||||||
@ -49,7 +51,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRestHeaderRegistration() {
|
public void testRestHeaderRegistration() {
|
||||||
new LdapRealm(ImmutableSettings.EMPTY, mock(LdapConnectionFactory.class), mock(LdapGroupToRoleMapper.class), restController);
|
new LdapRealm.Factory(mock(Environment.class), resourceWatcherService, restController);
|
||||||
verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
verify(restController).registerRelevantHeaders(UsernamePasswordToken.BASIC_AUTH_HEADER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +63,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
Settings settings = buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch);
|
Settings settings = buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch);
|
||||||
LdapConnectionFactory ldapFactory = new LdapConnectionFactory(settings);
|
LdapConnectionFactory ldapFactory = new LdapConnectionFactory(settings);
|
||||||
|
|
||||||
LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), restController);
|
LdapRealm ldap = new LdapRealm("test-ldap-realm", buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService));
|
||||||
|
|
||||||
User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
assertThat( user, notNullValue());
|
assertThat( user, notNullValue());
|
||||||
@ -76,7 +78,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
LdapConnectionFactory ldapFactory = new LdapConnectionFactory(
|
LdapConnectionFactory ldapFactory = new LdapConnectionFactory(
|
||||||
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
||||||
|
|
||||||
LdapRealm ldap = new LdapRealm(buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), restController);
|
LdapRealm ldap = new LdapRealm("test-ldap-realm", buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService));
|
||||||
|
|
||||||
User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
User user = ldap.authenticate(new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
assertThat( user, notNullValue());
|
assertThat( user, notNullValue());
|
||||||
@ -92,7 +94,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch) );
|
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch) );
|
||||||
|
|
||||||
ldapFactory = spy(ldapFactory);
|
ldapFactory = spy(ldapFactory);
|
||||||
LdapRealm ldap = new LdapRealm( buildCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), restController);
|
LdapRealm ldap = new LdapRealm("test-ldap-realm", buildCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService));
|
||||||
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
|
|
||||||
@ -111,7 +113,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
LdapGroupToRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
|
LdapGroupToRoleMapper roleMapper = buildGroupAsRoleMapper(resourceWatcherService);
|
||||||
|
|
||||||
ldapFactory = spy(ldapFactory);
|
ldapFactory = spy(ldapFactory);
|
||||||
LdapRealm ldap = new LdapRealm( buildCachingSettings(), ldapFactory, roleMapper, restController);
|
LdapRealm ldap = new LdapRealm("test-ldap-realm", buildCachingSettings(), ldapFactory, roleMapper);
|
||||||
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
|
|
||||||
@ -135,7 +137,7 @@ public class LdapRealmTest extends LdapTest {
|
|||||||
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
buildLdapSettings(ldapUrl(), userTemplate, groupSearchBase, isSubTreeSearch));
|
||||||
|
|
||||||
ldapFactory = spy(ldapFactory);
|
ldapFactory = spy(ldapFactory);
|
||||||
LdapRealm ldap = new LdapRealm( buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService), restController);
|
LdapRealm ldap = new LdapRealm("test-ldap-realm", buildNonCachingSettings(), ldapFactory, buildGroupAsRoleMapper(resourceWatcherService));
|
||||||
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
User user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
user = ldap.authenticate( new UsernamePasswordToken(VALID_USERNAME, SecuredStringTests.build(PASSWORD)));
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.shield.authc.ldap;
|
package org.elasticsearch.shield.authc.ldap;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.util.Providers;
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
import org.elasticsearch.shield.authc.support.SecuredStringTests;
|
||||||
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
import org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory;
|
||||||
@ -23,16 +24,17 @@ import static org.hamcrest.Matchers.hasItem;
|
|||||||
|
|
||||||
@Network
|
@Network
|
||||||
public class OpenLdapTests extends ElasticsearchTestCase {
|
public class OpenLdapTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
public static final String OPEN_LDAP_URL = "ldaps://54.200.235.244:636";
|
public static final String OPEN_LDAP_URL = "ldaps://54.200.235.244:636";
|
||||||
public static final String PASSWORD = "NickFuryHeartsES";
|
public static final String PASSWORD = "NickFuryHeartsES";
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setTrustStore() throws URISyntaxException {
|
public static void setTrustStore() throws URISyntaxException {
|
||||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
LdapSslSocketFactory.init(Providers.of(new SSLService(ImmutableSettings.builder()
|
||||||
.put("shield.ssl.keystore.path", filename)
|
.put("shield.ssl.keystore.path", filename)
|
||||||
.put("shield.ssl.keystore.password", "changeit")
|
.put("shield.ssl.keystore.password", "changeit")
|
||||||
.build()));
|
.build())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@ -41,17 +43,16 @@ public class OpenLdapTests extends ElasticsearchTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_standardLdapConnection_uid(){
|
public void test_standardLdapConnection_uid() {
|
||||||
//openldap does not use cn as naming attributes by default
|
//openldap does not use cn as naming attributes by default
|
||||||
|
|
||||||
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
String groupSearchBase = "ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||||
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
String userTemplate = "uid={0},ou=people,dc=oldap,dc=test,dc=elasticsearch,dc=com";
|
||||||
boolean isSubTreeSearch = true;
|
|
||||||
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(
|
LdapConnectionFactory connectionFactory = new LdapConnectionFactory(
|
||||||
LdapConnectionTests.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, isSubTreeSearch));
|
LdapConnectionTests.buildLdapSettings(OPEN_LDAP_URL, userTemplate, groupSearchBase, true));
|
||||||
|
|
||||||
String[] users = new String[]{"blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor"};
|
String[] users = new String[] { "blackwidow", "cap", "hawkeye", "hulk", "ironman", "thor" };
|
||||||
for(String user: users) {
|
for (String user : users) {
|
||||||
LdapConnection ldap = connectionFactory.open(user, SecuredStringTests.build(PASSWORD));
|
LdapConnection ldap = connectionFactory.open(user, SecuredStringTests.build(PASSWORD));
|
||||||
assertThat(ldap.groups(), hasItem(containsString("Avengers")));
|
assertThat(ldap.groups(), hasItem(containsString("Avengers")));
|
||||||
ldap.close();
|
ldap.close();
|
||||||
|
@ -68,24 +68,19 @@ public class CachingUsernamePasswordRealmTests extends ElasticsearchTestCase {
|
|||||||
static class FailingAuthenticationRealm extends CachingUsernamePasswordRealm {
|
static class FailingAuthenticationRealm extends CachingUsernamePasswordRealm {
|
||||||
|
|
||||||
FailingAuthenticationRealm(Settings settings) {
|
FailingAuthenticationRealm(Settings settings) {
|
||||||
super(settings);
|
super("failing", "failing-test", settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected User doAuthenticate(UsernamePasswordToken token) {
|
protected User doAuthenticate(UsernamePasswordToken token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String type() {
|
|
||||||
return "failing";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ThrowingAuthenticationRealm extends CachingUsernamePasswordRealm {
|
static class ThrowingAuthenticationRealm extends CachingUsernamePasswordRealm {
|
||||||
|
|
||||||
ThrowingAuthenticationRealm(Settings settings) {
|
ThrowingAuthenticationRealm(Settings settings) {
|
||||||
super(settings);
|
super("throwing", "throwing-test", settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -93,10 +88,6 @@ public class CachingUsernamePasswordRealmTests extends ElasticsearchTestCase {
|
|||||||
throw new RuntimeException("whatever exception");
|
throw new RuntimeException("whatever exception");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String type() {
|
|
||||||
return "throwing";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AlwaysAuthenticateCachingRealm extends CachingUsernamePasswordRealm {
|
static class AlwaysAuthenticateCachingRealm extends CachingUsernamePasswordRealm {
|
||||||
@ -104,7 +95,7 @@ public class CachingUsernamePasswordRealmTests extends ElasticsearchTestCase {
|
|||||||
public final AtomicInteger INVOCATION_COUNTER = new AtomicInteger(0);
|
public final AtomicInteger INVOCATION_COUNTER = new AtomicInteger(0);
|
||||||
|
|
||||||
AlwaysAuthenticateCachingRealm() {
|
AlwaysAuthenticateCachingRealm() {
|
||||||
super(ImmutableSettings.EMPTY);
|
super("always", "always-test", ImmutableSettings.EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -112,10 +103,5 @@ public class CachingUsernamePasswordRealmTests extends ElasticsearchTestCase {
|
|||||||
INVOCATION_COUNTER.incrementAndGet();
|
INVOCATION_COUNTER.incrementAndGet();
|
||||||
return new User.Simple(token.principal(), "testRole1", "testRole2");
|
return new User.Simple(token.principal(), "testRole1", "testRole2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String type() {
|
|
||||||
return "always";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +202,8 @@ public class ApacheDsEmbedded {
|
|||||||
*
|
*
|
||||||
* @param workDir the directory to be used for storing the data
|
* @param workDir the directory to be used for storing the data
|
||||||
* @param baseDn
|
* @param baseDn
|
||||||
* @param ldifFileName @throws Exception if there were some problems while initializing the system
|
* @param ldifFileName
|
||||||
|
* @throws Exception if there were some problems while initializing the system
|
||||||
*/
|
*/
|
||||||
private void initDirectoryService(File workDir, String baseDn, String ldifFileName) throws Exception {
|
private void initDirectoryService(File workDir, String baseDn, String ldifFileName) throws Exception {
|
||||||
// Initialize the LDAP service
|
// Initialize the LDAP service
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
package org.elasticsearch.shield.authc.support.ldap;
|
package org.elasticsearch.shield.authc.support.ldap;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.common.inject.util.Providers;
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.shield.ShieldSettingsException;
|
import org.elasticsearch.shield.ShieldSettingsException;
|
||||||
import org.elasticsearch.shield.ssl.SSLService;
|
|
||||||
import org.elasticsearch.shield.authc.ldap.LdapConnectionTests;
|
import org.elasticsearch.shield.authc.ldap.LdapConnectionTests;
|
||||||
|
import org.elasticsearch.shield.ssl.SSLService;
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@ -27,10 +28,10 @@ public class LdapSslSocketFactoryTests extends ElasticsearchTestCase {
|
|||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setTrustStore() throws URISyntaxException {
|
public static void setTrustStore() throws URISyntaxException {
|
||||||
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
File filename = new File(LdapConnectionTests.class.getResource("../support/ldap/ldaptrust.jks").toURI()).getAbsoluteFile();
|
||||||
LdapSslSocketFactory.init(new SSLService(ImmutableSettings.builder()
|
LdapSslSocketFactory.init(Providers.of(new SSLService(ImmutableSettings.builder()
|
||||||
.put("shield.ssl.keystore.path", filename)
|
.put("shield.ssl.keystore.path", filename)
|
||||||
.put("shield.ssl.keystore.password", "changeit")
|
.put("shield.ssl.keystore.password", "changeit")
|
||||||
.build()));
|
.build())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@ -39,19 +40,19 @@ public class LdapSslSocketFactoryTests extends ElasticsearchTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigure_1ldaps(){
|
public void testConfigure_1ldaps() {
|
||||||
String[] urls = new String[]{"ldaps://example.com:636"};
|
String[] urls = new String[] { "ldaps://example.com:636" };
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.builder();
|
||||||
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
||||||
ImmutableMap<String, Serializable> settings = builder.build();
|
ImmutableMap<String, Serializable> settings = builder.build();
|
||||||
assertThat(settings.get(LdapSslSocketFactory.JAVA_NAMING_LDAP_FACTORY_SOCKET),
|
assertThat((String) settings.get(LdapSslSocketFactory.JAVA_NAMING_LDAP_FACTORY_SOCKET),
|
||||||
Matchers.<Serializable>equalTo("org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory"));
|
equalTo("org.elasticsearch.shield.authc.support.ldap.LdapSslSocketFactory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigure_2ldaps(){
|
public void testConfigure_2ldaps() {
|
||||||
String[] urls = new String[]{"ldaps://primary.example.com:636", "LDAPS://secondary.example.com:10636"};
|
String[] urls = new String[] { "ldaps://primary.example.com:636", "LDAPS://secondary.example.com:10636" };
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
||||||
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
||||||
@ -60,8 +61,8 @@ public class LdapSslSocketFactoryTests extends ElasticsearchTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConfigure_2ldap(){
|
public void testConfigure_2ldap() {
|
||||||
String[] urls = new String[]{"ldap://primary.example.com:392", "LDAP://secondary.example.com:10392"};
|
String[] urls = new String[] { "ldap://primary.example.com:392", "LDAP://secondary.example.com:10392" };
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
||||||
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
||||||
@ -70,16 +71,16 @@ public class LdapSslSocketFactoryTests extends ElasticsearchTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ShieldSettingsException.class)
|
@Test(expected = ShieldSettingsException.class)
|
||||||
public void testConfigure_1ldaps_1ldap(){
|
public void testConfigure_1ldaps_1ldap() {
|
||||||
String[] urls = new String[]{"LDAPS://primary.example.com:636", "ldap://secondary.example.com:392"};
|
String[] urls = new String[] { "LDAPS://primary.example.com:636", "ldap://secondary.example.com:392" };
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
||||||
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ShieldSettingsException.class)
|
@Test(expected = ShieldSettingsException.class)
|
||||||
public void testConfigure_1ldap_1ldaps(){
|
public void testConfigure_1ldap_1ldaps() {
|
||||||
String[] urls = new String[]{"ldap://primary.example.com:392", "ldaps://secondary.example.com:636"};
|
String[] urls = new String[] { "ldap://primary.example.com:392", "ldaps://secondary.example.com:636" };
|
||||||
|
|
||||||
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
ImmutableMap.Builder<String, Serializable> builder = ImmutableMap.<String, Serializable>builder();
|
||||||
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
LdapSslSocketFactory.configureJndiSSL(urls, builder);
|
||||||
|
@ -24,8 +24,6 @@ import org.junit.Ignore;
|
|||||||
@ThreadLeakFilters(defaultFilters = true, filters = { LdapTest.ApachedsThreadLeakFilter.class })
|
@ThreadLeakFilters(defaultFilters = true, filters = { LdapTest.ApachedsThreadLeakFilter.class })
|
||||||
public abstract class LdapTest extends ElasticsearchTestCase {
|
public abstract class LdapTest extends ElasticsearchTestCase {
|
||||||
|
|
||||||
static String SETTINGS_PREFIX = LdapRealm.class.getPackage().getName().substring("com.elasticsearch.".length()) + '.';
|
|
||||||
|
|
||||||
private static ApacheDsEmbedded ldap;
|
private static ApacheDsEmbedded ldap;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -50,15 +48,15 @@ public abstract class LdapTest extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
public static Settings buildLdapSettings(String[] ldapUrl, String[] userTemplate, String groupSearchBase, boolean isSubTreeSearch) {
|
public static Settings buildLdapSettings(String[] ldapUrl, String[] userTemplate, String groupSearchBase, boolean isSubTreeSearch) {
|
||||||
return ImmutableSettings.builder()
|
return ImmutableSettings.builder()
|
||||||
.putArray(SETTINGS_PREFIX + LdapConnectionFactory.URLS_SETTING, ldapUrl)
|
.putArray(LdapConnectionFactory.URLS_SETTING, ldapUrl)
|
||||||
.putArray(SETTINGS_PREFIX + LdapConnectionFactory.USER_DN_TEMPLATES_SETTING, userTemplate)
|
.putArray(LdapConnectionFactory.USER_DN_TEMPLATES_SETTING, userTemplate)
|
||||||
.put(SETTINGS_PREFIX + LdapConnectionFactory.GROUP_SEARCH_BASEDN_SETTING, groupSearchBase)
|
.put(LdapConnectionFactory.GROUP_SEARCH_BASEDN_SETTING, groupSearchBase)
|
||||||
.put(SETTINGS_PREFIX + LdapConnectionFactory.GROUP_SEARCH_SUBTREE_SETTING, isSubTreeSearch).build();
|
.put(LdapConnectionFactory.GROUP_SEARCH_SUBTREE_SETTING, isSubTreeSearch).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Settings buildNonCachingSettings() {
|
protected Settings buildNonCachingSettings() {
|
||||||
return ImmutableSettings.builder()
|
return ImmutableSettings.builder()
|
||||||
.put("shield.authc.ldap."+LdapRealm.CACHE_TTL, -1)
|
.put(LdapRealm.CACHE_TTL, -1)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +67,7 @@ public abstract class LdapTest extends ElasticsearchTestCase {
|
|||||||
|
|
||||||
protected LdapGroupToRoleMapper buildGroupAsRoleMapper(ResourceWatcherService resourceWatcherService) {
|
protected LdapGroupToRoleMapper buildGroupAsRoleMapper(ResourceWatcherService resourceWatcherService) {
|
||||||
Settings settings = ImmutableSettings.builder()
|
Settings settings = ImmutableSettings.builder()
|
||||||
.put("shield.authc.ldap." + AbstractGroupToRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, true)
|
.put(AbstractGroupToRoleMapper.USE_UNMAPPED_GROUPS_AS_ROLES_SETTING, true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return new LdapGroupToRoleMapper(settings, new Environment(settings), resourceWatcherService);
|
return new LdapGroupToRoleMapper(settings, new Environment(settings), resourceWatcherService);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
package org.elasticsearch.shield.ssl;
|
package org.elasticsearch.shield.ssl;
|
||||||
|
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
@ -50,68 +49,6 @@ public class SSLServiceTests extends ElasticsearchTestCase {
|
|||||||
assertThat(ssl.createSSLEngine().getSSLParameters().getProtocols(), arrayContaining("TLSv1.2"));
|
assertThat(ssl.createSSLEngine().getSSLParameters().getProtocols(), arrayContaining("TLSv1.2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLDisabled_allDefaults(){
|
|
||||||
Settings settings = settingsBuilder().build();
|
|
||||||
assertSSLDisabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLEnabled_transportOffHttpOffLdapOff(){
|
|
||||||
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("shield.transport.ssl", false)
|
|
||||||
.put("shield.http.ssl", false)
|
|
||||||
.put("shield.authc.ldap.mode", "ldap")
|
|
||||||
.put("shield.authc.ldap.url", "ldap://example.com:389")
|
|
||||||
.build();
|
|
||||||
assertSSLDisabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLEnabled_transportOffHttpOffLdapMissingUrl() {
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("shield.transport.ssl", false)
|
|
||||||
.put("shield.http.ssl", false)
|
|
||||||
.put("shield.authc.ldap.mode", "active_dir") //SSL is on by default for a missing URL with active directory
|
|
||||||
.build();
|
|
||||||
assertSSLEnabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLEnabled_transportOffHttpOffLdapOn(){
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("shield.transport.ssl", false)
|
|
||||||
.put("shield.http.ssl", false)
|
|
||||||
.put("shield.authc.ldap.mode", "ldap")
|
|
||||||
.put("shield.authc.ldap.url", "ldaps://example.com:636")
|
|
||||||
.build();
|
|
||||||
assertSSLEnabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLEnabled_transportOffHttpOnLdapOff(){
|
|
||||||
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("shield.transport.ssl", false)
|
|
||||||
.put("shield.http.ssl", true)
|
|
||||||
.put("shield.authc.ldap.mode", "ldap")
|
|
||||||
.put("shield.authc.ldap.url", "ldap://example.com:389")
|
|
||||||
.build();
|
|
||||||
assertSSLEnabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSSLEnabled_transportOnHttpOffLdapOff(){
|
|
||||||
Settings settings = settingsBuilder()
|
|
||||||
.put("shield.transport.ssl", true)
|
|
||||||
.put("shield.http.ssl", false)
|
|
||||||
.put("shield.authc.ldap.mode", "ldap")
|
|
||||||
.put("shield.authc.ldap.url", "ldap://example.com:389")
|
|
||||||
.build();
|
|
||||||
assertSSLEnabled(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
|
public void testThatCustomTruststoreCanBeSpecified() throws Exception {
|
||||||
File testClientStore = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
|
File testClientStore = new File(getClass().getResource("/org/elasticsearch/shield/transport/ssl/certs/simple/testclient.jks").toURI());
|
||||||
@ -128,12 +65,4 @@ public class SSLServiceTests extends ElasticsearchTestCase {
|
|||||||
SSLEngine sslEngineWithTruststore = sslService.createSSLEngineWithTruststore(settingsBuilder.build());
|
SSLEngine sslEngineWithTruststore = sslService.createSSLEngineWithTruststore(settingsBuilder.build());
|
||||||
assertThat(sslEngineWithTruststore, is(not(nullValue())));
|
assertThat(sslEngineWithTruststore, is(not(nullValue())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSSLEnabled(Settings settings) {
|
|
||||||
assertThat(SSLService.isSSLEnabled(settings), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertSSLDisabled(Settings settings) {
|
|
||||||
assertThat(SSLService.isSSLEnabled(settings), is(false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import org.elasticsearch.common.os.OsUtils;
|
|||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.shield.ShieldPlugin;
|
import org.elasticsearch.shield.ShieldPlugin;
|
||||||
|
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
|
||||||
import org.elasticsearch.shield.authc.support.SecuredString;
|
import org.elasticsearch.shield.authc.support.SecuredString;
|
||||||
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
import org.elasticsearch.shield.authc.support.UsernamePasswordToken;
|
||||||
import org.elasticsearch.shield.signature.InternalSignatureService;
|
import org.elasticsearch.shield.signature.InternalSignatureService;
|
||||||
@ -89,8 +90,9 @@ public class ShieldSettingsSource extends ClusterDiscoveryConfiguration.UnicastZ
|
|||||||
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.node(nodeOrdinal))
|
ImmutableSettings.Builder builder = ImmutableSettings.builder().put(super.node(nodeOrdinal))
|
||||||
.put("shield.audit.enabled", RandomizedTest.randomBoolean())
|
.put("shield.audit.enabled", RandomizedTest.randomBoolean())
|
||||||
.put(InternalSignatureService.FILE_SETTING, writeFile(folder, "system_key", systemKey))
|
.put(InternalSignatureService.FILE_SETTING, writeFile(folder, "system_key", systemKey))
|
||||||
.put("shield.authc.esusers.files.users", writeFile(folder, "users", configUsers()))
|
.put("shield.authc.realms.esusers.type", ESUsersRealm.TYPE)
|
||||||
.put("shield.authc.esusers.files.users_roles", writeFile(folder, "users_roles", configUsersRoles()))
|
.put("shield.authc.realms.esusers.files.users", writeFile(folder, "users", configUsers()))
|
||||||
|
.put("shield.authc.realms.esusers.files.users_roles", writeFile(folder, "users_roles", configUsersRoles()))
|
||||||
.put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles()))
|
.put("shield.authz.store.files.roles", writeFile(folder, "roles.yml", configRoles()))
|
||||||
.put(getNodeSSLSettings());
|
.put(getNodeSSLSettings());
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user