Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add warnings for invalid realm order config (#51195) #51515

Merged
merged 8 commits into from
Jan 31, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@
public class RealmSettings {

public static final String PREFIX = "xpack.security.authc.realms.";
public static final String ORDER_SETTING_KEY = "order";

public static final Function<String, Setting.AffixSetting<Boolean>> ENABLED_SETTING = affixSetting("enabled",
key -> Setting.boolSetting(key, true, Setting.Property.NodeScope));
public static final Function<String, Setting.AffixSetting<Integer>> ORDER_SETTING = affixSetting("order",
public static final Function<String, Setting.AffixSetting<Integer>> ORDER_SETTING = affixSetting(ORDER_SETTING_KEY,
key -> Setting.intSetting(key, Integer.MAX_VALUE, Setting.Property.NodeScope));

public static String realmSettingPrefix(String type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ private DeprecationChecks() {
static List<BiFunction<Settings, PluginsAndModules, DeprecationIssue>> NODE_SETTINGS_CHECKS =
Collections.unmodifiableList(Arrays.asList(
NodeDeprecationChecks::checkPidfile,
NodeDeprecationChecks::checkProcessors
NodeDeprecationChecks::checkProcessors,
NodeDeprecationChecks::checkMissingRealmOrders,
NodeDeprecationChecks::checkUniqueRealmOrders
));

static List<Function<IndexMetaData, DeprecationIssue>> INDEX_SETTINGS_CHECKS =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
package org.elasticsearch.xpack.deprecation;

import org.elasticsearch.action.admin.cluster.node.info.PluginsAndModules;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;

import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

class NodeDeprecationChecks {

Expand All @@ -35,6 +41,61 @@ static DeprecationIssue checkProcessors(final Settings settings , final PluginsA
"https://www.elastic.co/guide/en/elasticsearch/reference/7.4/breaking-changes-7.4.html#deprecate-processors");
}

static DeprecationIssue checkMissingRealmOrders(final Settings settings, final PluginsAndModules pluginsAndModules) {
final String orderNotConfiguredRealms = RealmSettings.getRealmSettings(settings).entrySet()
.stream()
.filter(e -> Objects.isNull(e.getValue().get(RealmSettings.ORDER_SETTING_KEY)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to use Settings.hasValue instead here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

.map(e -> e.getKey().getName())
ywangd marked this conversation as resolved.
Show resolved Hide resolved
.collect(Collectors.joining("; "));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to collect them in a Set instead of a String. No signficant reason, it just seems "cleaner" to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


if (false == Strings.hasText(orderNotConfiguredRealms)) {
return null;
}

final String details = String.format(
Locale.ROOT,
"Found realms without order config: [%s]. In next major release, node will fail to start with missing realm order",
orderNotConfiguredRealms);
return new DeprecationIssue(
DeprecationIssue.Level.CRITICAL,
"Realm order will be required in next major release.",
"",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what url should be used here. The breaking change page will only be available once 8.0 is released?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a link to the deprecation snippet, which is still to be added in this PR, seee my other comment #51515 (comment) .

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per comments on the PR itself, we'll need to provide a URL here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the doc file and added the corresponding URL here.

details
);
}

static DeprecationIssue checkUniqueRealmOrders(final Settings settings, final PluginsAndModules pluginsAndModules) {
final Map<String, List<String>> orderToRealmName =
RealmSettings.getRealmSettings(settings).entrySet()
.stream()
.filter(e -> Objects.nonNull(e.getValue().get(RealmSettings.ORDER_SETTING_KEY)))
.collect(Collectors.groupingBy(
e -> e.getValue().get(RealmSettings.ORDER_SETTING_KEY),
Collectors.mapping(e -> e.getKey().getName(), Collectors.toList())));

String duplicateOrders = orderToRealmName.entrySet().stream()
.filter(entry -> entry.getValue().size() > 1)
.map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining("; "));

if (false == Strings.hasText(duplicateOrders)) {
return null;
}

final String details = String.format(
Locale.ROOT,
"Found multiple realms configured with the same order: [%s]. " +
"In next major release, node will fail to start with duplicated realm order",
duplicateOrders);

return new DeprecationIssue(
DeprecationIssue.Level.CRITICAL,
"Realm orders must be unique in next major release",
"",
details
);
}

private static DeprecationIssue checkDeprecatedSetting(
final Settings settings,
final PluginsAndModules pluginsAndModules,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@

import java.util.Collections;
import java.util.List;
import java.util.Locale;

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.startsWith;

public class NodeDeprecationChecksTests extends ESTestCase {

Expand Down Expand Up @@ -60,4 +62,48 @@ public void testCheckProcessors() {
assertSettingDeprecationsAndWarnings(new Setting<?>[]{EsExecutors.PROCESSORS_SETTING});
}

public void testCheckMissingRealmOrders() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like an inverse test as well - that realms with an order don't trigger an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added one test for correct realm order configs (2 realms of different orders)

String realmName = randomAlphaOfLengthBetween(4, 12);
String realmType = randomAlphaOfLengthBetween(4, 12);
final Settings settings =
Settings.builder()
.put("xpack.security.authc.realms." + realmType + "." + realmName + ".enabled", "true").build();

final PluginsAndModules pluginsAndModules = new PluginsAndModules(Collections.emptyList(), Collections.emptyList());
final List<DeprecationIssue> deprecationIssues =
DeprecationChecks.filterChecks(DeprecationChecks.NODE_SETTINGS_CHECKS, c -> c.apply(settings, pluginsAndModules));

assertEquals(1, deprecationIssues.size());
assertEquals(new DeprecationIssue(
DeprecationIssue.Level.CRITICAL,
"Realm order will be required in next major release.",
"",
String.format(
Locale.ROOT,
"Found realms without order config: [%s]. In next major release, node will fail to start with missing realm order",
realmName
)
), deprecationIssues.get(0));
}

public void testCheckUniqueRealmOrders() {
final int order = randomInt();
final Settings settings = Settings.builder()
.put("xpack.security.authc.realms."
+ randomAlphaOfLengthBetween(4, 12) + "." + randomAlphaOfLengthBetween(4, 12) + ".order", order)
.put("xpack.security.authc.realms."
+ randomAlphaOfLengthBetween(4, 12) + "." + randomAlphaOfLengthBetween(4, 12) + ".order", order)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add another realm with order + 1 and verify that it isn't reported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes we should. The test cases are not exhaustive. I have updated them to have better coverage.

.build();


final PluginsAndModules pluginsAndModules = new PluginsAndModules(Collections.emptyList(), Collections.emptyList());
final List<DeprecationIssue> deprecationIssues =
DeprecationChecks.filterChecks(DeprecationChecks.NODE_SETTINGS_CHECKS, c -> c.apply(settings, pluginsAndModules));

assertEquals(1, deprecationIssues.size());
assertEquals(DeprecationIssue.Level.CRITICAL, deprecationIssues.get(0).getLevel());
assertEquals("Realm orders must be unique in next major release", deprecationIssues.get(0).getMessage());
assertThat(deprecationIssues.get(0).getDetails(), startsWith("Found multiple realms configured with the same order:"));
}

}