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

Make order setting mandatory for Realm config #51195

Merged
merged 30 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
65cf24c
WIP: making realm order config mandatory
ywangd Jan 17, 2020
d186b0a
Support explicit order parameter for RealmConfig
ywangd Jan 19, 2020
82e08d2
Fix security plugin tests for required order param
ywangd Jan 19, 2020
71bfb3e
Fix more tests for required order param
ywangd Jan 19, 2020
5370163
Fix ci/2 failures
ywangd Jan 19, 2020
1132f5f
Merge branch 'master' into issue-37614-realm-order
elasticmachine Jan 19, 2020
7fa20a3
Fix more require order parameter failure
ywangd Jan 19, 2020
3d724e8
Enforce no same order for realms.
ywangd Jan 20, 2020
adca1bf
Fix duplicate order for tests
ywangd Jan 20, 2020
0f60b22
Add realm order to breaking change doc
ywangd Jan 20, 2020
3cb7a83
Start updating docs for realm order
ywangd Jan 20, 2020
22399ce
Add missing order config in docs
ywangd Jan 21, 2020
0edef24
Merge branch 'master' into issue-37614-realm-order
elasticmachine Jan 21, 2020
b439a49
Update docs/reference/migration/migrate_8_0/security.asciidoc
ywangd Jan 21, 2020
9548e2f
Merge branch 'master' into issue-37614-realm-order
elasticmachine Jan 21, 2020
a74482e
Update for docs feedback
ywangd Jan 21, 2020
e0aa65b
Update doc to address feedback
ywangd Jan 22, 2020
994c0af
More wording changes based on feedback
ywangd Jan 22, 2020
da8e7e3
Address feedback for docs
ywangd Jan 24, 2020
7fbf061
Address feedback to revert accident change
ywangd Jan 24, 2020
472b2d6
Merge remote-tracking branch 'origin/master' into issue-37614-realm-o…
ywangd Jan 24, 2020
64d0292
Update based on discussion with Tim.
ywangd Jan 24, 2020
aad6d19
Address feedback for consistent err msg
ywangd Jan 24, 2020
84cb684
Update x-pack/docs/en/security/authentication/custom-realm.asciidoc
ywangd Jan 27, 2020
4c61828
Update x-pack/docs/en/security/authentication/realm-chains.asciidoc
ywangd Jan 27, 2020
c264e31
Address feedback for docs
ywangd Jan 27, 2020
43fffa3
Merge remote-tracking branch 'origin/master' into issue-37614-realm-o…
ywangd Jan 27, 2020
0614cbc
Update docs/reference/migration/migrate_8_0/security.asciidoc
ywangd Jan 28, 2020
fe13c71
Update x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/s…
ywangd Jan 28, 2020
ad7a1b5
Merge remote-tracking branch 'origin/master' into issue-37614-realm-o…
ywangd Jan 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions docs/reference/migration/migrate_8_0/security.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@
//Installation and Upgrade Guide

//tag::notable-breaking-changes[]
[float]
==== The realm `order` setting is required

The `xpack.security.authc.realms.*.*.order` setting is now required and must be
ywangd marked this conversation as resolved.
Show resolved Hide resolved
specified for each explicitly configured realm. Each value must be unique.
The cluster will fail to start if the requirements are not met.

For example, the following configuration is invalid:
[source,yaml]
--------------------------------------------------
xpack.security.authc.realms.kerberos.kerb1:
keytab.path: es.keytab
remove_realm_name: false
--------------------------------------------------

And must be configured as:
[source,yaml]
--------------------------------------------------
xpack.security.authc.realms.kerberos.kerb1:
order: 0
keytab.path: es.keytab
remove_realm_name: false
--------------------------------------------------

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

Expand Down Expand Up @@ -79,17 +102,17 @@ It is now an error to configure any SSL settings for
For example, the following configuration is invalid:
[source,yaml]
--------------------------------------------------
xpack.security.http.ssl.certificate: elasticsearch.crt
xpack.security.http.ssl.key: elasticsearch.key
xpack.security.http.ssl.certificate: elasticsearch.crt
xpack.security.http.ssl.key: elasticsearch.key
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
--------------------------------------------------

And must be configured as either:
[source,yaml]
--------------------------------------------------
xpack.security.http.ssl.enabled: true <1>
xpack.security.http.ssl.certificate: elasticsearch.crt
xpack.security.http.ssl.key: elasticsearch.key
xpack.security.http.ssl.certificate: elasticsearch.crt
xpack.security.http.ssl.key: elasticsearch.key
xpack.security.http.ssl.certificate_authorities: [ "corporate-ca.crt" ]
--------------------------------------------------
<1> or `false`.
Expand All @@ -110,4 +133,3 @@ a certificate and key through use of the `xpack.security.http.ssl.keystore.path`
setting or the `xpack.security.http.ssl.certificate` and
`xpack.security.http.ssl.key` settings.


7 changes: 4 additions & 3 deletions docs/reference/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ namespace in `elasticsearch.yml`. For example:
xpack.security.authc.realms:

native.realm1: <1>
order: 0
order: 0 <2>
...

ldap.realm2:
Expand All @@ -204,6 +204,8 @@ xpack.security.authc.realms:
<1> Specifies the type of realm (for example, `native`, `ldap`,
`active_directory`, `pki`, `file`, `kerberos`, `saml`) and the realm name. This
information is required.
<2> Specifies priority of a realm in the realm chain. This information
is required.

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

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

`enabled`::
Indicates whether a realm is enabled. You can use this setting to disable a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ realm and map Active Directory users and groups to roles in the role mapping fil

. Add a realm configuration of type `active_directory` to `elasticsearch.yml`
under the `xpack.security.authc.realms.active_directory` namespace.
At a minimum, you must specify the Active Directory `domain_name`.
If you are configuring multiple realms, you should also
explicitly set the `order` attribute to control the order in which the realms
are consulted during authentication.
At a minimum, you must specify the Active Directory `domain_name` and `order`.
+
ywangd marked this conversation as resolved.
Show resolved Hide resolved
--
See <<ref-ad-settings>> for all of the options you can set for an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ However, multiple bind operations might be needed to find the correct user DN.

.. Add a realm configuration of to `elasticsearch.yml` under the
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
the `url` of the LDAP server, and set `user_search.base_dn` to the container DN
where the users are searched for.
If you are configuring multiple realms, you should also explicitly set the
`order` attribute to control the order in which the realms are consulted during
the `url` and `order` of the LDAP server, and set `user_search.base_dn` to the
container DN where the users are searched for.
The `order` attribute to control the order in which the realms are consulted during
authentication. See <<ref-ldap-settings>> for all of the options you can set for
Copy link
Contributor

Choose a reason for hiding this comment

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

This last phrase doesn't make sense, I would avoid describing again what order does.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will do thanks

an `ldap` realm.
+
Expand Down Expand Up @@ -73,7 +72,7 @@ realms you specify are used for authentication. If you also want to use the
.. Add a realm configuration to `elasticsearch.yml` in the
`xpack.security.authc.realms.ldap` namespace. At a minimum, you must specify
the `url` of the LDAP server, and specify at least one template with the
`user_dn_templates` option. If you are configuring multiple realms, you should
`user_dn_templates` option. If you are configuring multiple realms, you must
also explicitly set the `order` attribute to control the order in which the
realms are consulted during authentication.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would remove

If you are configuring multiple realms, you must ...

altogether.

Copy link
Member Author

Choose a reason for hiding this comment

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

Somehow missed this occurrence ... Will remove. Thanks

See <<ref-ldap-settings>> for all of the options you can set for an `ldap` realm.
Expand Down Expand Up @@ -206,6 +205,7 @@ xpack:
realms:
ldap:
ldap1:
order: 0
ywangd marked this conversation as resolved.
Show resolved Hide resolved
metadata: cn
--------------------------------------------------
--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ clients connect directly to {es}.

. Add a realm configuration for a `pki` realm to `elasticsearch.yml` under the
`xpack.security.authc.realms.pki` namespace.
If you are configuring multiple realms, you should
explicitly set the `order` attribute. See <<ref-pki-settings>> for all of the
options you can set for a `pki` realm.
You must explicitly set the `order` attribute. See <<ref-pki-settings>> for all
of the options you can set for a `pki` realm.
+
--
For example, the following snippet shows the most basic `pki` realm configuration:
Expand Down Expand Up @@ -61,6 +60,7 @@ xpack:
realms:
pki:
pki1:
order: 1
ywangd marked this conversation as resolved.
Show resolved Hide resolved
username_pattern: "EMAILADDRESS=(.*?)(?:,|$)"
------------------------------------------------------------

Expand Down Expand Up @@ -118,6 +118,7 @@ xpack:
realms:
pki:
pki1:
order: 1
truststore:
path: "pki1_truststore.jks"
------------------------------------------------------------
Expand Down
9 changes: 4 additions & 5 deletions x-pack/docs/en/security/authentication/custom-realm.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,10 @@ under the `xpack.security.authc.realms` namespace.
You must define your realm within the namespace that matchesto the type defined
by the extension.
The options you can set depend on the settings exposed by the custom realm.
If you are configuring multiple realms, you should also explicitly set the
`order` attribute to control the order in which the realms are consulted during
authentication. You should make sure each configured realm has a distinct
`order` setting. In the event that two or more realms have the same `order`,
they will be processed in realm `name` order.
At a minimum, you must explicitly set the `order` attribute to control the
order in which the realms are consulted during authentication. You must also
make sure each configured realm has a distinct `order` setting. In the event
that two or more realms have the same `order`, the cluster will fail to start.
ywangd marked this conversation as resolved.
Show resolved Hide resolved
+
IMPORTANT: When you configure realms in `elasticsearch.yml`, only the
realms you specify are used for authentication. If you also want to use the
Expand Down
4 changes: 2 additions & 2 deletions x-pack/docs/en/security/authentication/realm-chains.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<<realms,Realms>> live within a _realm chain_. It is essentially a prioritized
list of configured realms (typically of various types). Realms are consulted in
ascending order (that is to say, the realm with the lowest `order` value is
consulted first). You should make sure each configured realm has a distinct
consulted first). You must make sure each configured realm has a distinct
`order` setting. In the event that two or more realms have the same `order`,
they are processed in `name` order.
the cluster will fail to start.
ywangd marked this conversation as resolved.
Show resolved Hide resolved

During the authentication process, {stack} {security-features} consult and try
to authenticate the request one realm at a time. Once one of the realms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,15 @@ public RealmConfig(RealmIdentifier identifier, Settings settings, Environment en
this.identifier = identifier;
this.settings = settings;
this.env = env;
this.threadContext = threadContext;
this.enabled = getSetting(RealmSettings.ENABLED_SETTING);
if (false == hasSetting(RealmSettings.ORDER_SETTING.apply(type()))) {
throw new IllegalArgumentException("'order' is a mandatory parameter for realm config. " +
"Found invalid config for realm: '" + identifier.name + "'\n" +
"Please see the breaking changes documentation."
ywangd marked this conversation as resolved.
Show resolved Hide resolved
);
}
ywangd marked this conversation as resolved.
Show resolved Hide resolved
this.order = getSetting(RealmSettings.ORDER_SETTING);
this.threadContext = threadContext;
}

public RealmIdentifier identifier() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* * 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.xpack.core.security.authc;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;
import org.mockito.Mockito;

import static org.hamcrest.Matchers.containsString;

public class RealmConfigTests extends ESTestCase {

private RealmConfig.RealmIdentifier realmIdentifier;
private Settings globalSettings;
private Environment environment;
private ThreadContext threadContext;

@Before
public void setUp() throws Exception {
realmIdentifier = new RealmConfig.RealmIdentifier(randomAlphaOfLengthBetween(4, 12), randomAlphaOfLengthBetween(4,12));
environment = Mockito.mock(Environment.class);
globalSettings = Settings.builder().put("path.home", createTempDir()).build();
threadContext = new ThreadContext(globalSettings);
super.setUp();
}

public void testWillPassWhenOrderSettingIsConfigured() {
Settings settings = Settings.builder()
.put(globalSettings)
.put(RealmSettings.realmSettingPrefix(realmIdentifier) + "order", 0)
.build();

RealmConfig realmConfig = new RealmConfig(realmIdentifier, settings, environment, threadContext);
assertEquals(0, realmConfig.order);
}

public void testWillFailWhenOrderSettingIsMissing() {
Settings settings = Settings.builder().put(globalSettings).build();
var e = expectThrows(IllegalArgumentException.class, () -> new RealmConfig(realmIdentifier, settings, environment, threadContext));
assertThat(e.getMessage(), containsString("'order' is a mandatory parameter for realm config"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ protected List<Realm> initRealms() throws Exception {
List<Realm> realms = new ArrayList<>();
List<String> kerberosRealmNames = new ArrayList<>();
Map<String, Set<String>> nameToRealmIdentifier = new HashMap<>();
Map<Integer, Set<String>> orderToRealmName = new HashMap<>();
for (RealmConfig.RealmIdentifier identifier: realmsSettings.keySet()) {
Realm.Factory factory = factories.get(identifier.getType());
if (factory == null) {
Expand Down Expand Up @@ -218,9 +219,13 @@ protected List<Realm> initRealms() throws Exception {
Realm realm = factory.create(config);
nameToRealmIdentifier.computeIfAbsent(realm.name(), k ->
new HashSet<>()).add(RealmSettings.realmSettingPrefix(realm.type()) + realm.name());
orderToRealmName.computeIfAbsent(realm.order(), k -> new HashSet<>())
.add(realm.name());
realms.add(realm);
}

checkUniqueOrders(orderToRealmName);

if (!realms.isEmpty()) {
Collections.sort(realms);
} else {
Expand Down Expand Up @@ -305,15 +310,34 @@ public void usageStats(ActionListener<Map<String, Object>> listener) {
private void addNativeRealms(List<Realm> realms) throws Exception {
Realm.Factory fileRealm = factories.get(FileRealmSettings.TYPE);
if (fileRealm != null) {
var realmIdentifier = new RealmConfig.RealmIdentifier(FileRealmSettings.TYPE, "default_" + FileRealmSettings.TYPE);
realms.add(fileRealm.create(new RealmConfig(
new RealmConfig.RealmIdentifier(FileRealmSettings.TYPE, "default_" + FileRealmSettings.TYPE),
settings, env, threadContext)));
realmIdentifier,
ensureOrderSetting(settings, realmIdentifier, Integer.MIN_VALUE + 1),
env, threadContext)));
}
Realm.Factory indexRealmFactory = factories.get(NativeRealmSettings.TYPE);
if (indexRealmFactory != null) {
var realmIdentifier = new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "default_" + NativeRealmSettings.TYPE);
realms.add(indexRealmFactory.create(new RealmConfig(
new RealmConfig.RealmIdentifier(NativeRealmSettings.TYPE, "default_" + NativeRealmSettings.TYPE),
settings, env, threadContext)));
realmIdentifier,
ensureOrderSetting(settings, realmIdentifier, Integer.MIN_VALUE + 2),
env, threadContext)));
}
}

private Settings ensureOrderSetting(Settings settings, RealmConfig.RealmIdentifier realmIdentifier, int order) {
String orderSettingKey = RealmSettings.realmSettingPrefix(realmIdentifier) + "order";
return Settings.builder().put(settings).put(orderSettingKey, order).build();
}

private void checkUniqueOrders(Map<Integer, Set<String>> orderToRealmName) {
String duplicateOrders = orderToRealmName.entrySet().stream()
.filter(entry -> entry.getValue().size() > 1)
.map(entry -> entry.getKey() + ": " + entry.getValue())
.collect(Collectors.joining("; "));
if (Strings.hasText(duplicateOrders)) {
throw new IllegalArgumentException("Found multiple realms configured with the same order: " + duplicateOrders + "");
ywangd marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.security.authc.AuthenticationResult;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.esnative.ClientReservedRealm;
import org.elasticsearch.xpack.core.security.authc.support.Hasher;
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
Expand Down Expand Up @@ -63,7 +64,11 @@ public class ReservedRealm extends CachingUsernamePasswordRealm {

public ReservedRealm(Environment env, Settings settings, NativeUsersStore nativeUsersStore, AnonymousUser anonymousUser,
SecurityIndexManager securityIndex, ThreadPool threadPool) {
super(new RealmConfig(new RealmConfig.RealmIdentifier(TYPE, TYPE), settings, env, threadPool.getThreadContext()), threadPool);
super(new RealmConfig(new RealmConfig.RealmIdentifier(TYPE, TYPE),
Settings.builder()
.put(settings)
.put(RealmSettings.realmSettingPrefix(new RealmConfig.RealmIdentifier(TYPE, TYPE)) + "order", Integer.MIN_VALUE)
.build(), env, threadPool.getThreadContext()), threadPool);
this.nativeUsersStore = nativeUsersStore;
this.realmEnabled = XPackSettings.RESERVED_REALM_ENABLED_SETTING.get(settings);
this.anonymousUser = anonymousUser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ protected String nodeClientUsername() {
protected SecureString nodeClientPassword() {
return new SecureString(TEST_PASSWORD.toCharArray());
}

public static void addSSLSettingsForNodePEMFiles(Settings.Builder builder, String prefix, boolean hostnameVerificationEnabled) {
addSSLSettingsForPEMFiles(builder, prefix,
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import org.elasticsearch.xpack.core.security.action.oidc.OpenIdConnectLogoutResponse;
import org.elasticsearch.xpack.core.security.authc.Authentication;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
import org.elasticsearch.xpack.core.security.authc.oidc.OpenIdConnectRealmSettings;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.ssl.SSLService;
Expand Down Expand Up @@ -88,9 +89,11 @@ public class TransportOpenIdConnectLogoutActionTests extends OpenIdConnectTestCa

@Before
public void setup() throws Exception {
final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("oidc", REALM_NAME);
final Settings settings = getBasicRealmSettings()
.put(XPackSettings.TOKEN_SERVICE_ENABLED_SETTING.getKey(), true)
.put("path.home", createTempDir())
.put(RealmSettings.getFullSettingKey(realmIdentifier, RealmSettings.ORDER_SETTING), 0)
.build();
final Settings sslSettings = Settings.builder()
.put("xpack.security.authc.realms.oidc.oidc-realm.ssl.verification_mode", "certificate")
Expand Down Expand Up @@ -179,8 +182,6 @@ public void setup() throws Exception {

final Environment env = TestEnvironment.newEnvironment(settings);

final RealmConfig.RealmIdentifier realmIdentifier = new RealmConfig.RealmIdentifier("oidc", REALM_NAME);

final RealmConfig realmConfig = new RealmConfig(realmIdentifier, settings, env, threadContext);
oidcRealm = new OpenIdConnectRealm(realmConfig, new SSLService(TestEnvironment.newEnvironment(sslSettings)),
mock(UserRoleMapper.class), mock(ResourceWatcherService.class));
Expand Down
Loading