Skip to content

Commit 83a819a

Browse files
authored
Make order setting required for Realm config (#51195)
The order config must be explicitly specified for each realm. It must also be unique for each realm. This is a breaking change and will begin to take effect in 8.0 Resolves: #37614
1 parent e8562a4 commit 83a819a

File tree

55 files changed

+444
-157
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+444
-157
lines changed

docs/reference/migration/migrate_8_0/security.asciidoc

+27-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66
//Installation and Upgrade Guide
77

88
//tag::notable-breaking-changes[]
9+
[float]
10+
==== The realm `order` setting is required
11+
12+
The `xpack.security.authc.realms.{type}.{name}.order` setting is now required and must be
13+
specified for each explicitly configured realm. Each value must be unique.
14+
The cluster will fail to start if the requirements are not met.
15+
16+
For example, the following configuration is invalid:
17+
[source,yaml]
18+
--------------------------------------------------
19+
xpack.security.authc.realms.kerberos.kerb1:
20+
keytab.path: es.keytab
21+
remove_realm_name: false
22+
--------------------------------------------------
23+
24+
And must be configured as:
25+
[source,yaml]
26+
--------------------------------------------------
27+
xpack.security.authc.realms.kerberos.kerb1:
28+
order: 0
29+
keytab.path: es.keytab
30+
remove_realm_name: false
31+
--------------------------------------------------
932

1033
// end::notable-breaking-changes[]
1134

@@ -79,17 +102,17 @@ It is now an error to configure any SSL settings for
79102
For example, the following configuration is invalid:
80103
[source,yaml]
81104
--------------------------------------------------
82-
xpack.security.http.ssl.certificate: elasticsearch.crt
83-
xpack.security.http.ssl.key: elasticsearch.key
105+
xpack.security.http.ssl.certificate: elasticsearch.crt
106+
xpack.security.http.ssl.key: elasticsearch.key
84107
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
85108
--------------------------------------------------
86109

87110
And must be configured as either:
88111
[source,yaml]
89112
--------------------------------------------------
90113
xpack.security.http.ssl.enabled: true <1>
91-
xpack.security.http.ssl.certificate: elasticsearch.crt
92-
xpack.security.http.ssl.key: elasticsearch.key
114+
xpack.security.http.ssl.certificate: elasticsearch.crt
115+
xpack.security.http.ssl.key: elasticsearch.key
93116
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
94117
--------------------------------------------------
95118
<1> or `false`.
@@ -109,5 +132,3 @@ It is now an error to enable SSL for the HTTP (Rest) server without also configu
109132
a certificate and key through use of the `xpack.security.http.ssl.keystore.path`
110133
setting or the `xpack.security.http.ssl.certificate` and
111134
`xpack.security.http.ssl.key` settings.
112-
113-

docs/reference/settings/security-settings.asciidoc

+4-3
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ namespace in `elasticsearch.yml`. For example:
189189
xpack.security.authc.realms:
190190
191191
native.realm1: <1>
192-
order: 0
192+
order: 0 <2>
193193
...
194194
195195
ldap.realm2:
@@ -204,6 +204,8 @@ xpack.security.authc.realms:
204204
<1> Specifies the type of realm (for example, `native`, `ldap`,
205205
`active_directory`, `pki`, `file`, `kerberos`, `saml`) and the realm name. This
206206
information is required.
207+
<2> Specifies priority of a realm in the realm chain. This information
208+
is required.
207209

208210
The valid settings vary depending on the realm type. For more
209211
information, see <<setting-up-authentication>>.
@@ -214,8 +216,7 @@ information, see <<setting-up-authentication>>.
214216

215217
`order`::
216218
The priority of the realm within the realm chain. Realms with a lower order are
217-
consulted first. Although not required, use of this setting is strongly
218-
recommended when you configure multiple realms. Defaults to `Integer.MAX_VALUE`.
219+
consulted first. The value must be unique for each realm. This setting is required.
219220

220221
`enabled`::
221222
Indicates whether a realm is enabled. You can use this setting to disable a

x-pack/docs/en/security/authentication/configuring-active-directory-realm.asciidoc

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ realm and map Active Directory users and groups to roles in the role mapping fil
33

44
. Add a realm configuration of type `active_directory` to `elasticsearch.yml`
55
under the `xpack.security.authc.realms.active_directory` namespace.
6-
At a minimum, you must specify the Active Directory `domain_name`.
7-
If you are configuring multiple realms, you should also
8-
explicitly set the `order` attribute to control the order in which the realms
9-
are consulted during authentication.
6+
At a minimum, you must specify the Active Directory `domain_name` and `order`.
107
+
118
--
129
See <<ref-ad-settings>> for all of the options you can set for an

x-pack/docs/en/security/authentication/configuring-ldap-realm.asciidoc

+6-9
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,9 @@ However, multiple bind operations might be needed to find the correct user DN.
2121

2222
.. Add a realm configuration of to `elasticsearch.yml` under the
2323
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
24-
the `url` of the LDAP server, and set `user_search.base_dn` to the container DN
25-
where the users are searched for.
26-
If you are configuring multiple realms, you should also explicitly set the
27-
`order` attribute to control the order in which the realms are consulted during
28-
authentication. See <<ref-ldap-settings>> for all of the options you can set for
24+
the `url` and `order` of the LDAP server, and set `user_search.base_dn` to the
25+
container DN where the users are searched for.
26+
See <<ref-ldap-settings>> for all of the options you can set for
2927
an `ldap` realm.
3028
+
3129
--
@@ -72,10 +70,8 @@ realms you specify are used for authentication. If you also want to use the
7270

7371
.. Add a realm configuration to `elasticsearch.yml` in the
7472
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
75-
the `url` of the LDAP server, and specify at least one template with the
76-
`user_dn_templates` option. If you are configuring multiple realms, you should
77-
also explicitly set the `order` attribute to control the order in which the
78-
realms are consulted during authentication.
73+
the `url` and `order` of the LDAP server, and specify at least one template
74+
with the `user_dn_templates` option.
7975
See <<ref-ldap-settings>> for all of the options you can set for an `ldap` realm.
8076
+
8177
--
@@ -206,6 +202,7 @@ xpack:
206202
realms:
207203
ldap:
208204
ldap1:
205+
order: 0
209206
metadata: cn
210207
--------------------------------------------------
211208
--

x-pack/docs/en/security/authentication/configuring-pki-realm.asciidoc

+4-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ clients connect directly to {es}.
2121

2222
. Add a realm configuration for a `pki` realm to `elasticsearch.yml` under the
2323
`xpack.security.authc.realms.pki` namespace.
24-
If you are configuring multiple realms, you should
25-
explicitly set the `order` attribute. See <<ref-pki-settings>> for all of the
26-
options you can set for a `pki` realm.
24+
You must explicitly set the `order` attribute. See <<ref-pki-settings>> for all
25+
of the options you can set for a `pki` realm.
2726
+
2827
--
2928
For example, the following snippet shows the most basic `pki` realm configuration:
@@ -61,6 +60,7 @@ xpack:
6160
realms:
6261
pki:
6362
pki1:
63+
order: 1
6464
username_pattern: "EMAILADDRESS=(.*?)(?:,|$)"
6565
------------------------------------------------------------
6666

@@ -118,6 +118,7 @@ xpack:
118118
realms:
119119
pki:
120120
pki1:
121+
order: 1
121122
truststore:
122123
path: "pki1_truststore.jks"
123124
------------------------------------------------------------

x-pack/docs/en/security/authentication/custom-realm.asciidoc

+4-5
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,10 @@ under the `xpack.security.authc.realms` namespace.
8989
You must define your realm within the namespace that matchesto the type defined
9090
by the extension.
9191
The options you can set depend on the settings exposed by the custom realm.
92-
If you are configuring multiple realms, you should also explicitly set the
93-
`order` attribute to control the order in which the realms are consulted during
94-
authentication. You should make sure each configured realm has a distinct
95-
`order` setting. In the event that two or more realms have the same `order`,
96-
they will be processed in realm `name` order.
92+
At a minimum, you must explicitly set the `order` attribute to control the
93+
order in which the realms are consulted during authentication. You must also
94+
make sure each configured realm has a distinct `order` setting. In the event
95+
that two or more realms have the same `order`, the node will fail to start.
9796
+
9897
IMPORTANT: When you configure realms in `elasticsearch.yml`, only the
9998
realms you specify are used for authentication. If you also want to use the

x-pack/docs/en/security/authentication/realm-chains.asciidoc

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
<<realms,Realms>> live within a _realm chain_. It is essentially a prioritized
66
list of configured realms (typically of various types). Realms are consulted in
77
ascending order (that is to say, the realm with the lowest `order` value is
8-
consulted first). You should make sure each configured realm has a distinct
8+
consulted first). You must make sure each configured realm has a distinct
99
`order` setting. In the event that two or more realms have the same `order`,
10-
they are processed in `name` order.
10+
the node will fail to start.
1111

1212
During the authentication process, {stack} {security-features} consult and try
1313
to authenticate the request one realm at a time. Once one of the realms

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/RealmConfig.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,15 @@ public RealmConfig(RealmIdentifier identifier, Settings settings, Environment en
2727
this.identifier = identifier;
2828
this.settings = settings;
2929
this.env = env;
30+
this.threadContext = threadContext;
3031
this.enabled = getSetting(RealmSettings.ENABLED_SETTING);
32+
if (false == hasSetting(RealmSettings.ORDER_SETTING.apply(type()))) {
33+
throw new IllegalArgumentException("'order' is a mandatory parameter for realm config. " +
34+
"Found invalid config for realm: '" + identifier.name + "'\n" +
35+
"Please see the breaking changes documentation."
36+
);
37+
}
3138
this.order = getSetting(RealmSettings.ORDER_SETTING);
32-
this.threadContext = threadContext;
3339
}
3440

3541
public RealmIdentifier identifier() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
*
3+
* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
4+
* * or more contributor license agreements. Licensed under the Elastic License;
5+
* * you may not use this file except in compliance with the Elastic License.
6+
*
7+
*/
8+
9+
package org.elasticsearch.xpack.core.security.authc;
10+
11+
import org.elasticsearch.common.settings.Settings;
12+
import org.elasticsearch.common.util.concurrent.ThreadContext;
13+
import org.elasticsearch.env.Environment;
14+
import org.elasticsearch.test.ESTestCase;
15+
import org.junit.Before;
16+
import org.mockito.Mockito;
17+
18+
import static org.hamcrest.Matchers.containsString;
19+
20+
public class RealmConfigTests extends ESTestCase {
21+
22+
private RealmConfig.RealmIdentifier realmIdentifier;
23+
private Settings globalSettings;
24+
private Environment environment;
25+
private ThreadContext threadContext;
26+
27+
@Before
28+
public void setUp() throws Exception {
29+
realmIdentifier = new RealmConfig.RealmIdentifier(randomAlphaOfLengthBetween(4, 12), randomAlphaOfLengthBetween(4,12));
30+
environment = Mockito.mock(Environment.class);
31+
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
32+
threadContext = new ThreadContext(globalSettings);
33+
super.setUp();
34+
}
35+
36+
public void testWillPassWhenOrderSettingIsConfigured() {
37+
Settings settings = Settings.builder()
38+
.put(globalSettings)
39+
.put(RealmSettings.realmSettingPrefix(realmIdentifier) + "order", 0)
40+
.build();
41+
42+
RealmConfig realmConfig = new RealmConfig(realmIdentifier, settings, environment, threadContext);
43+
assertEquals(0, realmConfig.order);
44+
}
45+
46+
public void testWillFailWhenOrderSettingIsMissing() {
47+
Settings settings = Settings.builder().put(globalSettings).build();
48+
var e = expectThrows(IllegalArgumentException.class, () -> new RealmConfig(realmIdentifier, settings, environment, threadContext));
49+
assertThat(e.getMessage(), containsString("'order' is a mandatory parameter for realm config"));
50+
}
51+
}

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/Realms.java

+28-4
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ protected List<Realm> initRealms() throws Exception {
186186
List<Realm> realms = new ArrayList<>();
187187
List<String> kerberosRealmNames = new ArrayList<>();
188188
Map<String, Set<String>> nameToRealmIdentifier = new HashMap<>();
189+
Map<Integer, Set<String>> orderToRealmName = new HashMap<>();
189190
for (RealmConfig.RealmIdentifier identifier: realmsSettings.keySet()) {
190191
Realm.Factory factory = factories.get(identifier.getType());
191192
if (factory == null) {
@@ -218,9 +219,13 @@ protected List<Realm> initRealms() throws Exception {
218219
Realm realm = factory.create(config);
219220
nameToRealmIdentifier.computeIfAbsent(realm.name(), k ->
220221
new HashSet<>()).add(RealmSettings.realmSettingPrefix(realm.type()) + realm.name());
222+
orderToRealmName.computeIfAbsent(realm.order(), k -> new HashSet<>())
223+
.add(realm.name());
221224
realms.add(realm);
222225
}
223226

227+
checkUniqueOrders(orderToRealmName);
228+
224229
if (!realms.isEmpty()) {
225230
Collections.sort(realms);
226231
} else {
@@ -305,15 +310,34 @@ public void usageStats(ActionListener<Map<String, Object>> listener) {
305310
private void addNativeRealms(List<Realm> realms) throws Exception {
306311
Realm.Factory fileRealm = factories.get(FileRealmSettings.TYPE);
307312
if (fileRealm != null) {
313+
var realmIdentifier = new RealmConfig.RealmIdentifier(FileRealmSettings.TYPE, "default_" + FileRealmSettings.TYPE);
308314
realms.add(fileRealm.create(new RealmConfig(
309-
new RealmConfig.RealmIdentifier(FileRealmSettings.TYPE, "default_" + FileRealmSettings.TYPE),
310-
settings, env, threadContext)));
315+
realmIdentifier,
316+
ensureOrderSetting(settings, realmIdentifier, Integer.MIN_VALUE + 1),
317+
env, threadContext)));
311318
}
312319
Realm.Factory indexRealmFactory = factories.get(NativeRealmSettings.TYPE);
313320
if (indexRealmFactory != null) {
321+
var realmIdentifier = new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "default_" + NativeRealmSettings.TYPE);
314322
realms.add(indexRealmFactory.create(new RealmConfig(
315-
new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "default_" + NativeRealmSettings.TYPE),
316-
settings, env, threadContext)));
323+
realmIdentifier,
324+
ensureOrderSetting(settings, realmIdentifier, Integer.MIN_VALUE + 2),
325+
env, threadContext)));
326+
}
327+
}
328+
329+
private Settings ensureOrderSetting(Settings settings, RealmConfig.RealmIdentifier realmIdentifier, int order) {
330+
String orderSettingKey = RealmSettings.realmSettingPrefix(realmIdentifier) + "order";
331+
return Settings.builder().put(settings).put(orderSettingKey, order).build();
332+
}
333+
334+
private void checkUniqueOrders(Map<Integer, Set<String>> orderToRealmName) {
335+
String duplicateOrders = orderToRealmName.entrySet().stream()
336+
.filter(entry -> entry.getValue().size() > 1)
337+
.map(entry -> entry.getKey() + ": " + entry.getValue())
338+
.collect(Collectors.joining("; "));
339+
if (Strings.hasText(duplicateOrders)) {
340+
throw new IllegalArgumentException("Found multiple realms configured with the same order: " + duplicateOrders);
317341
}
318342
}
319343

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/esnative/ReservedRealm.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.xpack.core.XPackSettings;
1919
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
2020
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
21+
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
2122
import org.elasticsearch.xpack.core.security.authc.esnative.ClientReservedRealm;
2223
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
2324
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
@@ -63,7 +64,11 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {
6364

6465
public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser,
6566
SecurityIndexManager securityIndex, ThreadPool threadPool) {
66-
super(new RealmConfig(new RealmConfig.RealmIdentifier(TYPE, TYPE), settings, env, threadPool.getThreadContext()), threadPool);
67+
super(new RealmConfig(new RealmConfig.RealmIdentifier(TYPE, TYPE),
68+
Settings.builder()
69+
.put(settings)
70+
.put(RealmSettings.realmSettingPrefix(new RealmConfig.RealmIdentifier(TYPE, TYPE)) + "order", Integer.MIN_VALUE)
71+
.build(), env, threadPool.getThreadContext()), threadPool);
6772
this.nativeUsersStore = nativeUsersStore;
6873
this.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
6974
this.anonymousUser = anonymousUser;

x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ protected String nodeClientUsername() {
185185
protected SecureString nodeClientPassword() {
186186
return new SecureString(TEST_PASSWORD.toCharArray());
187187
}
188-
188+
189189
public static void addSSLSettingsForNodePEMFiles(Settings.Builder builder, String prefix, boolean hostnameVerificationEnabled) {
190190
addSSLSettingsForPEMFiles(builder, prefix,
191191
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode",

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/oidc/TransportOpenIdConnectLogoutActionTests.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectLogoutResponse;
4545
import org.elasticsearch.xpack.core.security.authc.Authentication;
4646
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
47+
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
4748
import org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings;
4849
import org.elasticsearch.xpack.core.security.user.User;
4950
import org.elasticsearch.xpack.core.ssl.SSLService;
@@ -88,9 +89,11 @@ public class TransportOpenIdConnectLogoutActionTests extends OpenIdConnectTestCa
8889

8990
@Before
9091
public void setup() throws Exception {
92+
final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("oidc", REALM_NAME);
9193
final Settings settings = getBasicRealmSettings()
9294
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true)
9395
.put("path.home", createTempDir())
96+
.put(RealmSettings.getFullSettingKey(realmIdentifier, RealmSettings.ORDER_SETTING), 0)
9497
.build();
9598
final Settings sslSettings = Settings.builder()
9699
.put("xpack.security.authc.realms.oidc.oidc-realm.ssl.verification_mode", "certificate")
@@ -179,8 +182,6 @@ public void setup() throws Exception {
179182

180183
final Environment env = TestEnvironment.newEnvironment(settings);
181184

182-
final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("oidc", REALM_NAME);
183-
184185
final RealmConfig realmConfig = new RealmConfig(realmIdentifier, settings, env, threadContext);
185186
oidcRealm = new OpenIdConnectRealm(realmConfig, new SSLService(TestEnvironment.newEnvironment(sslSettings)),
186187
mock(UserRoleMapper.class), mock(ResourceWatcherService.class));

0 commit comments

Comments
 (0)