Skip to content

Commit d7aaa19

Browse files
Fix AD realm additional metadata (#47179)
Due to a regression bug the metadata Active Directory realm setting is ignored (it works correctly for the LDAP realm type). This commit redresses it. Closes #45848
1 parent ac90603 commit d7aaa19

File tree

10 files changed

+93
-23
lines changed

10 files changed

+93
-23
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public static Set<Setting.AffixSetting<?>> getSettings(String type) {
4646
settings.addAll(LdapUserSearchSessionFactorySettings.getSettings());
4747
settings.addAll(DelegatedAuthorizationSettings.getSettings(type));
4848
}
49-
settings.addAll(LdapMetaDataResolverSettings.getSettings());
49+
settings.addAll(LdapMetaDataResolverSettings.getSettings(type));
5050
settings.addAll(RealmSettings.getStandardSettings(type));
5151
return settings;
5252
}

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/ldap/support/LdapMetaDataResolverSettings.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,18 @@
77

88
import org.elasticsearch.common.settings.Setting;
99
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
10-
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
1110

1211
import java.util.Collections;
1312
import java.util.List;
1413
import java.util.function.Function;
1514

1615
public final class LdapMetaDataResolverSettings {
17-
public static final Setting.AffixSetting<List<String>> ADDITIONAL_META_DATA_SETTING = Setting.affixKeySetting(
18-
RealmSettings.realmSettingPrefix(LdapRealmSettings.LDAP_TYPE), "metadata",
19-
key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
16+
public static final Function<String, Setting.AffixSetting<List<String>>> ADDITIONAL_META_DATA_SETTING = RealmSettings.affixSetting(
17+
"metadata", key -> Setting.listSetting(key, Collections.emptyList(), Function.identity(), Setting.Property.NodeScope));
2018

2119
private LdapMetaDataResolverSettings() {}
2220

23-
public static List<Setting.AffixSetting<?>> getSettings() {
24-
return Collections.singletonList(ADDITIONAL_META_DATA_SETTING);
21+
public static List<Setting.AffixSetting<?>> getSettings(String type) {
22+
return Collections.singletonList(ADDITIONAL_META_DATA_SETTING.apply(type));
2523
}
2624
}

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.unboundid.ldap.sdk.LDAPException;
1010
import com.unboundid.ldap.sdk.SimpleBindRequest;
1111
import org.elasticsearch.action.ActionListener;
12+
import org.elasticsearch.common.CharArrays;
1213
import org.elasticsearch.common.Strings;
1314
import org.elasticsearch.common.settings.SecureString;
1415
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
@@ -18,9 +19,7 @@
1819
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
1920
import org.elasticsearch.xpack.core.security.authc.ldap.LdapSessionFactorySettings;
2021
import org.elasticsearch.xpack.core.security.authc.ldap.SearchGroupsResolverSettings;
21-
import org.elasticsearch.common.CharArrays;
2222
import org.elasticsearch.xpack.core.ssl.SSLService;
23-
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
2423
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
2524
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession.GroupsResolver;
2625
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
@@ -41,7 +40,6 @@ public class LdapSessionFactory extends SessionFactory {
4140

4241
private final String[] userDnTemplates;
4342
private final GroupsResolver groupResolver;
44-
private final LdapMetaDataResolver metaDataResolver;
4543

4644
public LdapSessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
4745
super(config, sslService, threadPool);
@@ -52,7 +50,6 @@ public LdapSessionFactory(RealmConfig config, SSLService sslService, ThreadPool
5250
}
5351
logger.info("Realm [{}] is in user-dn-template mode: [{}]", config.name(), userDnTemplates);
5452
groupResolver = groupResolver(config);
55-
metaDataResolver = new LdapMetaDataResolver(config, ignoreReferralErrors);
5653
}
5754

5855
/**

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.apache.logging.log4j.Logger;
1616
import org.apache.logging.log4j.message.ParameterizedMessage;
1717
import org.elasticsearch.action.ActionListener;
18+
import org.elasticsearch.common.CharArrays;
1819
import org.elasticsearch.common.Nullable;
1920
import org.elasticsearch.common.lease.Releasable;
2021
import org.elasticsearch.common.settings.SecureString;
@@ -24,9 +25,7 @@
2425
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
2526
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
2627
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
27-
import org.elasticsearch.common.CharArrays;
2828
import org.elasticsearch.xpack.core.ssl.SSLService;
29-
import org.elasticsearch.xpack.security.authc.ldap.support.LdapMetaDataResolver;
3029
import org.elasticsearch.xpack.security.authc.ldap.support.LdapSession;
3130
import org.elasticsearch.xpack.security.authc.ldap.support.LdapUtils;
3231
import org.elasticsearch.xpack.security.authc.ldap.support.SessionFactory;
@@ -45,10 +44,8 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
4544
private final LDAPConnectionPool connectionPool;
4645

4746
final SimpleBindRequest bindCredentials;
48-
final LdapMetaDataResolver metaDataResolver;
4947
final LdapSession.GroupsResolver groupResolver;
5048

51-
5249
/**
5350
* @param config the configuration for the realm
5451
* @param sslService the ssl service to get a socket factory or context from
@@ -63,7 +60,6 @@ abstract class PoolingSessionFactory extends SessionFactory implements Releasabl
6360
ThreadPool threadPool) throws LDAPException {
6461
super(config, sslService, threadPool);
6562
this.groupResolver = groupResolver;
66-
this.metaDataResolver = new LdapMetaDataResolver(config, ignoreReferralErrors);
6763

6864
final byte[] bindPassword;
6965
if (config.hasSetting(LEGACY_BIND_PASSWORD)) {

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/ldap/support/SessionFactory.java

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public abstract class SessionFactory {
6060
protected final boolean sslUsed;
6161
protected final boolean ignoreReferralErrors;
6262

63+
protected final LdapMetaDataResolver metaDataResolver;
64+
6365
protected SessionFactory(RealmConfig config, SSLService sslService, ThreadPool threadPool) {
6466
this.config = config;
6567
this.logger = LogManager.getLogger(getClass());
@@ -78,6 +80,7 @@ protected SessionFactory(RealmConfig config, SSLService sslService, ThreadPool t
7880
this.serverSet = serverSet(config, sslService, ldapServers);
7981
this.sslUsed = ldapServers.ssl;
8082
this.ignoreReferralErrors = config.getSetting(SessionFactorySettings.IGNORE_REFERRAL_ERRORS_SETTING);
83+
this.metaDataResolver = new LdapMetaDataResolver(config, ignoreReferralErrors);
8184
}
8285

8386
/**

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/ActiveDirectoryRealmTests.java

+71-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import com.unboundid.ldap.sdk.schema.Schema;
1616
import org.elasticsearch.action.ActionListener;
1717
import org.elasticsearch.action.support.PlainActionFuture;
18+
import org.elasticsearch.client.Client;
1819
import org.elasticsearch.common.Strings;
20+
import org.elasticsearch.common.bytes.BytesArray;
1921
import org.elasticsearch.common.settings.MockSecureSettings;
2022
import org.elasticsearch.common.settings.SecureString;
2123
import org.elasticsearch.common.settings.Settings;
@@ -24,6 +26,9 @@
2426
import org.elasticsearch.env.TestEnvironment;
2527
import org.elasticsearch.license.TestUtils;
2628
import org.elasticsearch.license.XPackLicenseState;
29+
import org.elasticsearch.script.ScriptModule;
30+
import org.elasticsearch.script.ScriptService;
31+
import org.elasticsearch.script.mustache.MustacheScriptEngine;
2732
import org.elasticsearch.test.ESTestCase;
2833
import org.elasticsearch.threadpool.TestThreadPool;
2934
import org.elasticsearch.threadpool.ThreadPool;
@@ -34,31 +39,36 @@
3439
import org.elasticsearch.xpack.core.security.authc.ldap.LdapRealmSettings;
3540
import org.elasticsearch.xpack.core.security.authc.ldap.PoolingSessionFactorySettings;
3641
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapLoadBalancingSettings;
42+
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapMetaDataResolverSettings;
3743
import org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings;
3844
import org.elasticsearch.xpack.core.security.authc.support.CachingUsernamePasswordRealmSettings;
3945
import org.elasticsearch.xpack.core.security.authc.support.DnRoleMapperSettings;
4046
import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken;
47+
import org.elasticsearch.xpack.core.security.authc.support.mapper.ExpressionRoleMapping;
48+
import org.elasticsearch.xpack.core.security.authc.support.mapper.TemplateRoleName;
4149
import org.elasticsearch.xpack.core.security.user.User;
4250
import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
4351
import org.elasticsearch.xpack.core.ssl.SSLService;
4452
import org.elasticsearch.xpack.core.ssl.VerificationMode;
4553
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.DownLevelADAuthenticator;
4654
import org.elasticsearch.xpack.security.authc.ldap.ActiveDirectorySessionFactory.UpnADAuthenticator;
4755
import org.elasticsearch.xpack.security.authc.support.DnRoleMapper;
56+
import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
57+
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
4858
import org.junit.After;
4959
import org.junit.Before;
5060
import org.junit.BeforeClass;
5161

5262
import java.security.AccessController;
5363
import java.security.PrivilegedExceptionAction;
5464
import java.util.ArrayList;
65+
import java.util.Arrays;
5566
import java.util.Collections;
5667
import java.util.List;
5768
import java.util.Locale;
5869
import java.util.Map;
5970

6071
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.getFullSettingKey;
61-
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.HOSTNAME_VERIFICATION_SETTING;
6272
import static org.elasticsearch.xpack.core.security.authc.ldap.support.SessionFactorySettings.URLS_SETTING;
6373
import static org.hamcrest.Matchers.arrayContaining;
6474
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
@@ -71,9 +81,11 @@
7181
import static org.hamcrest.Matchers.notNullValue;
7282
import static org.mockito.Matchers.any;
7383
import static org.mockito.Matchers.eq;
84+
import static org.mockito.Mockito.mock;
7485
import static org.mockito.Mockito.spy;
7586
import static org.mockito.Mockito.times;
7687
import static org.mockito.Mockito.verify;
88+
import static org.mockito.Mockito.when;
7789

7890
/**
7991
* Active Directory Realm tests that use the UnboundID In Memory Directory Server
@@ -354,6 +366,62 @@ public void testRealmMapsUsersToRoles() throws Exception {
354366
assertThat(user.roles(), arrayContainingInAnyOrder(equalTo("group_role"), equalTo("user_role")));
355367
}
356368

369+
/**
370+
* This tests template role mappings (see
371+
* {@link TemplateRoleName}) with an LDAP realm, using a additional
372+
* metadata field (see {@link LdapMetaDataResolverSettings#ADDITIONAL_META_DATA_SETTING}).
373+
*/
374+
public void testRealmWithTemplatedRoleMapping() throws Exception {
375+
final RealmConfig.RealmIdentifier realmId = realmId("testRealmWithTemplatedRoleMapping");
376+
Settings settings = settings(realmId, Settings.builder()
377+
.put(getFullSettingKey(realmId, LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "departmentNumber")
378+
.build());
379+
RealmConfig config = setupRealm(realmId, settings);
380+
ActiveDirectorySessionFactory sessionFactory = new ActiveDirectorySessionFactory(config, sslService, threadPool);
381+
382+
SecurityIndexManager mockSecurityIndex = mock(SecurityIndexManager.class);
383+
when(mockSecurityIndex.isAvailable()).thenReturn(true);
384+
when(mockSecurityIndex.isIndexUpToDate()).thenReturn(true);
385+
when(mockSecurityIndex.isMappingUpToDate()).thenReturn(true);
386+
387+
Client mockClient = mock(Client.class);
388+
when(mockClient.threadPool()).thenReturn(threadPool);
389+
390+
final ScriptService scriptService = new ScriptService(settings, Collections.singletonMap(MustacheScriptEngine.NAME,
391+
new MustacheScriptEngine()), ScriptModule.CORE_CONTEXTS);
392+
NativeRoleMappingStore roleMapper = new NativeRoleMappingStore(settings, mockClient, mockSecurityIndex, scriptService) {
393+
@Override
394+
protected void loadMappings(ActionListener<List<ExpressionRoleMapping>> listener) {
395+
listener.onResponse(
396+
Arrays.asList(
397+
this.buildMapping("m1", new BytesArray("{" +
398+
"\"role_templates\":[{\"template\":{\"source\":\"_role_{{metadata.departmentNumber}}\"}}]," +
399+
"\"enabled\":true," +
400+
"\"rules\":{ " +
401+
" \"field\":{\"realm.name\":\"testrealmwithtemplatedrolemapping\"}" +
402+
"}}"))));
403+
}
404+
};
405+
LdapRealm realm = new LdapRealm(config, sessionFactory, roleMapper, threadPool);
406+
realm.initialize(Collections.singleton(realm), licenseState);
407+
408+
PlainActionFuture<AuthenticationResult> future = new PlainActionFuture<>();
409+
realm.authenticate(new UsernamePasswordToken("CN=Thor", new SecureString(PASSWORD)), future);
410+
AuthenticationResult result = future.actionGet();
411+
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
412+
User user = result.getUser();
413+
assertThat(user, notNullValue());
414+
assertThat(user.roles(), arrayContaining("_role_13"));
415+
416+
future = new PlainActionFuture<>();
417+
realm.authenticate(new UsernamePasswordToken("CN=ironman", new SecureString(PASSWORD)), future);
418+
result = future.actionGet();
419+
assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS));
420+
user = result.getUser();
421+
assertThat(user, notNullValue());
422+
assertThat(user.roles(), arrayContaining("_role_12"));
423+
}
424+
357425
public void testRealmUsageStats() throws Exception {
358426
final RealmConfig.RealmIdentifier realmId = realmId("testRealmUsageStats");
359427
String loadBalanceType = randomFrom("failover", "round_robin");
@@ -469,7 +537,8 @@ private Settings settings(RealmConfig.RealmIdentifier realmIdentifier, Settings
469537
builder.put(getFullSettingKey(realmIdentifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM),
470538
VerificationMode.CERTIFICATE);
471539
} else {
472-
builder.put(getFullSettingKey(realmIdentifier, HOSTNAME_VERIFICATION_SETTING), false);
540+
builder.put(getFullSettingKey(realmIdentifier, SSLConfigurationSettings.VERIFICATION_MODE_SETTING_REALM),
541+
VerificationMode.NONE);
473542
}
474543
return builder.put(extraSettings).build();
475544
}

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/LdapRealmTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,8 @@ public void testLdapRealmWithTemplatedRoleMapping() throws Exception {
416416
Settings settings = Settings.builder()
417417
.put(defaultGlobalSettings)
418418
.put(buildLdapSettings(ldapUrls(), userTemplate, groupSearchBase, LdapSearchScope.SUB_TREE))
419-
.put(getFullSettingKey(REALM_IDENTIFIER.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "uid")
419+
.put(getFullSettingKey(REALM_IDENTIFIER.getName(),
420+
LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.apply(LdapRealmSettings.LDAP_TYPE)), "uid")
420421
.build();
421422
RealmConfig config = getRealmConfig(REALM_IDENTIFIER, settings);
422423

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ldap/support/LdapMetaDataResolverTests.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ public void testParseSettings() throws Exception {
3939
final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier(LdapRealmSettings.LDAP_TYPE, "my_ldap");
4040
final Settings settings = Settings.builder()
4141
.put("path.home", createTempDir())
42-
.putList(RealmSettings.getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING),
42+
.putList(RealmSettings.getFullSettingKey(realmId.getName(),
43+
LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.apply(LdapRealmSettings.LDAP_TYPE)),
4344
"cn", "uid")
4445
.build();
4546
RealmConfig config = new RealmConfig(realmId,

x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/authc/ldap/ad.ldif

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ userPrincipalName: [email protected]
2929
userPrincipalName: [email protected]
3030
userPassword: password
3131
sn: Stark
32+
departmentNumber: 12
3233

3334
dn: CN=Thor,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com
3435
objectclass: user
@@ -42,3 +43,4 @@ tokenGroups:: AQUAAAAAAAUVAAAA4rc20emZjwwpdMkMUQQAAA==
4243
userPrincipalName: [email protected]
4344
userPassword: password
4445
sn: Stark
46+
departmentNumber: 13

x-pack/qa/openldap-tests/src/test/java/org/elasticsearch/test/OpenLdapTests.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ public void testStandardLdapConnectionHostnameVerificationSuccess() throws Excep
228228
public void testResolveSingleValuedAttributeFromConnection() throws Exception {
229229
final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test");
230230
final Settings settings = Settings.builder()
231-
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "cn", "sn")
231+
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.apply("ldap")),
232+
"cn", "sn")
232233
.build();
233234
final RealmConfig config = new RealmConfig(realmId, settings,
234235
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
@@ -244,7 +245,8 @@ public void testResolveSingleValuedAttributeFromConnection() throws Exception {
244245
public void testResolveMultiValuedAttributeFromConnection() throws Exception {
245246
final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test");
246247
final Settings settings = Settings.builder()
247-
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "objectClass")
248+
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.apply("ldap")),
249+
"objectClass")
248250
.build();
249251
final RealmConfig config = new RealmConfig(realmId, settings,
250252
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
@@ -260,7 +262,8 @@ public void testResolveMultiValuedAttributeFromConnection() throws Exception {
260262
public void testResolveMissingAttributeFromConnection() throws Exception {
261263
final RealmConfig.RealmIdentifier realmId = new RealmConfig.RealmIdentifier("ldap", "oldap-test");
262264
final Settings settings = Settings.builder()
263-
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING), "alias")
265+
.putList(getFullSettingKey(realmId.getName(), LdapMetaDataResolverSettings.ADDITIONAL_META_DATA_SETTING.apply("ldap")),
266+
"alias")
264267
.build();
265268
final RealmConfig config = new RealmConfig(realmId, settings,
266269
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));

0 commit comments

Comments
 (0)