Settings filter should rely directly on realm settings (elastic/x-pack-elasticsearch#1669)

The security module had special cases for realm settings that should be filtered,
but since elastic/x-pack-elasticsearch@2c76a13 / elastic/elasticsearch#4311 it's possible to use the existing realm
setting objects to do that.

Original commit: elastic/x-pack-elasticsearch@0651afe987
This commit is contained in:
Tim Vernum 2017-06-08 18:05:02 +10:00 committed by GitHub
parent 7aa1114eca
commit 29c11c30f3
6 changed files with 59 additions and 30 deletions

View File

@ -376,7 +376,7 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
filters.add("xpack.notification.pagerduty." + PagerDutyAccount.SERVICE_KEY_SETTING);
filters.add("xpack.notification.pagerduty.account.*." + PagerDutyAccount.SERVICE_KEY_SETTING);
filters.add("xpack.notification.hipchat.account.*.auth_token");
filters.addAll(security.getSettingsFilter());
filters.addAll(security.getSettingsFilter(extensionsService));
filters.addAll(MonitoringSettings.getSettingsFilter());
if (transportClientMode == false) {
for (XPackExtension extension : extensionsService.getExtensions()) {

View File

@ -113,15 +113,14 @@ import org.elasticsearch.xpack.security.authc.TokenService;
import org.elasticsearch.xpack.security.authc.esnative.NativeRealm;
import org.elasticsearch.xpack.security.authc.esnative.NativeUsersStore;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
import org.elasticsearch.xpack.security.authc.support.mapper.expressiondsl.ExpressionParser;
import org.elasticsearch.xpack.security.authz.AuthorizationService;
import org.elasticsearch.xpack.security.authz.RoleDescriptor;
import org.elasticsearch.xpack.security.authz.SecuritySearchOperationListener;
import org.elasticsearch.xpack.security.authz.accesscontrol.OptOutQueryCache;
import org.elasticsearch.xpack.security.authz.accesscontrol.SecurityIndexSearcherWrapper;
import org.elasticsearch.xpack.security.authz.SecuritySearchOperationListener;
import org.elasticsearch.xpack.security.authz.accesscontrol.SetSecurityUserProcessor;
import org.elasticsearch.xpack.security.authz.permission.FieldPermissionsCache;
import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
@ -481,19 +480,15 @@ public class Security implements ActionPlugin, IngestPlugin, NetworkPlugin {
}
public List<String> getSettingsFilter() {
public List<String> getSettingsFilter(@Nullable XPackExtensionsService extensionsService) {
ArrayList<String> settingsFilter = new ArrayList<>();
String[] asArray = settings.getAsArray(setting("hide_settings"));
for (String pattern : asArray) {
settingsFilter.add(pattern);
}
settingsFilter.add(setting("authc.realms.*.bind_dn"));
settingsFilter.add(setting("authc.realms.*.bind_password"));
settingsFilter.add(setting("authc.realms.*." + SessionFactory.HOSTNAME_VERIFICATION_SETTING));
settingsFilter.add(setting("authc.realms.*.truststore.password"));
settingsFilter.add(setting("authc.realms.*.truststore.path"));
settingsFilter.add(setting("authc.realms.*.truststore.algorithm"));
final List<XPackExtension> extensions = extensionsService == null ? Collections.emptyList() : extensionsService.getExtensions();
settingsFilter.addAll(RealmSettings.getSettingsFilter(extensions));
// hide settings where we don't define them - they are part of a group...
settingsFilter.add("transport.profiles.*." + setting("*"));

View File

@ -10,12 +10,14 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.extensions.XPackExtension;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static org.elasticsearch.common.Strings.isNullOrEmpty;
import static org.elasticsearch.xpack.security.Security.setting;
@ -53,6 +55,14 @@ public class RealmSettings {
settingsList.add(getGroupSetting(extensions));
}
public static Collection<String> getSettingsFilter(List<XPackExtension> extensions) {
return getSettingsByRealm(extensions).values().stream()
.flatMap(Collection::stream)
.filter(Setting::isFiltered)
.map(setting -> PREFIX + "*." + setting.getKey())
.collect(Collectors.toSet());
}
/**
* Extract the child {@link Settings} for the {@link #PREFIX realms prefix}.
* The top level names in the returned <code>Settings</code> will be the names of the configured realms.
@ -89,18 +99,27 @@ public class RealmSettings {
}
private static Consumer<Settings> getSettingsValidator(List<XPackExtension> extensions) {
final Map<String, Set<Setting<?>>> childSettings = new HashMap<>(InternalRealms.getSettings());
final Map<String, Set<Setting<?>>> childSettings = getSettingsByRealm(extensions);
childSettings.forEach(RealmSettings::verify);
return validator(childSettings);
}
/**
* @return A map from <em>realm-type</em> to a collection of <code>Setting</code> objects.
* @see InternalRealms#getSettings()
*/
private static Map<String, Set<Setting<?>>> getSettingsByRealm(List<XPackExtension> extensions) {
final Map<String, Set<Setting<?>>> settingsByRealm = new HashMap<>(InternalRealms.getSettings());
if (extensions != null) {
extensions.forEach(ext -> {
final Map<String, Set<Setting<?>>> extSettings = ext.getRealmSettings();
extSettings.keySet().stream().filter(childSettings::containsKey).forEach(type -> {
extSettings.keySet().stream().filter(settingsByRealm::containsKey).forEach(type -> {
throw new IllegalArgumentException("duplicate realm type " + type);
});
childSettings.putAll(extSettings);
settingsByRealm.putAll(extSettings);
});
}
childSettings.forEach(RealmSettings::verify);
return validator(childSettings);
return settingsByRealm;
}
private static void verify(String type, Set<Setting<?>> settings) {

View File

@ -72,8 +72,10 @@ class LdapUserSearchSessionFactory extends SessionFactory {
private static final Setting<Optional<String>> HEALTH_CHECK_DN = new Setting<>("user_search.pool.health_check.dn", (String) null,
Optional::ofNullable, Setting.Property.NodeScope);
private static final Setting<String> BIND_DN = Setting.simpleString("bind_dn", Setting.Property.NodeScope);
private static final Setting<String> BIND_PASSWORD = Setting.simpleString("bind_password", Setting.Property.NodeScope);
private static final Setting<String> BIND_DN = Setting.simpleString("bind_dn",
Setting.Property.NodeScope, Setting.Property.Filtered);
private static final Setting<String> BIND_PASSWORD = Setting.simpleString("bind_password",
Setting.Property.NodeScope, Setting.Property.Filtered);
private final String userSearchBaseDn;
private final LdapSearchScope scope;

View File

@ -213,16 +213,11 @@ public abstract class SessionFactory {
settings.addAll(LdapLoadBalancing.getSettings());
settings.add(Setting.listSetting(URLS_SETTING, Collections.emptyList(), Function.identity(),
Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_CONNECTION_SETTING, TIMEOUT_DEFAULT,
Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_READ_SETTING, TIMEOUT_DEFAULT,
Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_LDAP_SETTING, TIMEOUT_DEFAULT,
Setting.Property.NodeScope));
settings.add(Setting.boolSetting(HOSTNAME_VERIFICATION_SETTING, true,
Setting.Property.NodeScope));
settings.add(Setting.boolSetting(FOLLOW_REFERRALS_SETTING, true,
Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_CONNECTION_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_TCP_READ_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.timeSetting(TIMEOUT_LDAP_SETTING, TIMEOUT_DEFAULT, Setting.Property.NodeScope));
settings.add(Setting.boolSetting(HOSTNAME_VERIFICATION_SETTING, true, Setting.Property.NodeScope, Setting.Property.Filtered));
settings.add(Setting.boolSetting(FOLLOW_REFERRALS_SETTING, true, Setting.Property.NodeScope));
settings.add(IGNORE_REFERRAL_ERRORS_SETTING);
settings.addAll(SSLConfigurationSettings.withPrefix("ssl.").getAllSettings());
return settings;

View File

@ -9,6 +9,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -31,14 +32,18 @@ import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
import org.elasticsearch.xpack.security.authc.Realm;
import org.elasticsearch.xpack.security.authc.Realms;
import org.elasticsearch.xpack.security.authc.file.FileRealm;
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
import org.elasticsearch.xpack.ssl.SSLService;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasItem;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class SecurityTests extends ESTestCase {
private Security security = null;
public static class DummyExtension extends XPackExtension {
private String realmType;
DummyExtension(String realmType) {
@ -59,10 +64,12 @@ public class SecurityTests extends ESTestCase {
}
private Collection<Object> createComponents(Settings testSettings, XPackExtension... extensions) throws Exception {
Settings settings = Settings.builder().put(testSettings)
.put("path.home", createTempDir()).build();
if (security != null) {
throw new IllegalStateException("Security object already exists (" + security + ")");
}
Settings settings = Settings.builder().put(testSettings).put("path.home", createTempDir()).build();
Environment env = new Environment(settings);
Security security = new Security(settings, env, new XPackLicenseState(), new SSLService(settings, env));
security = new Security(settings, env, new XPackLicenseState(), new SSLService(settings, env));
ThreadPool threadPool = mock(ThreadPool.class);
ClusterService clusterService = mock(ClusterService.class);
settings = Security.additionalSettings(settings, false);
@ -173,4 +180,15 @@ public class SecurityTests extends ESTestCase {
assertThat(badHttp.getMessage(), containsString(Security.NAME4));
assertThat(badHttp.getMessage(), containsString(NetworkModule.HTTP_TYPE_KEY));
}
public void testSettingFilter() throws Exception {
createComponents(Settings.EMPTY);
final List<String> filter = security.getSettingsFilter(null);
assertThat(filter, hasItem(Security.setting("authc.realms.*.bind_dn")));
assertThat(filter, hasItem(Security.setting("authc.realms.*.bind_password")));
assertThat(filter, hasItem(Security.setting("authc.realms.*." + SessionFactory.HOSTNAME_VERIFICATION_SETTING)));
assertThat(filter, hasItem(Security.setting("authc.realms.*.ssl.truststore.password")));
assertThat(filter, hasItem(Security.setting("authc.realms.*.ssl.truststore.path")));
assertThat(filter, hasItem(Security.setting("authc.realms.*.ssl.truststore.algorithm")));
}
}