Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ def setCommonTestConfig(Test task) {
// this is needed to reflect access system env map.
task.jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED"
task.jvmArgs += "--add-opens=java.base/java.util=ALL-UNNAMED"
task.jvmArgs += "--add-opens=java.base/java.nio=ALL-UNNAMED"
task.jvmArgs += "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
task.jvmArgs += "-Dio.netty.transport.noNative=true"
task.retry {
failOnPassedAfterRetry = false
maxRetries = 5
Expand Down Expand Up @@ -302,6 +305,9 @@ test {
// this is needed to reflect access system env map.
jvmArgs += "--add-opens=java.base/java.io=ALL-UNNAMED"
jvmArgs += "--add-opens=java.base/java.util=ALL-UNNAMED"
jvmArgs += "--add-opens=java.base/java.nio=ALL-UNNAMED"
jvmArgs += "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
jvmArgs += "-Dio.netty.transport.noNative=true"
Comment on lines +308 to +310
Copy link
Member Author

Choose a reason for hiding this comment

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

Trying to fix JDK 25 failures from https://productionresultssa13.blob.core.windows.net/actions-results/976a235c-0711-4a54-a0d8-2c07ccb05d97/workflow-job-run-bace64fb-7753-5237-83f3-6a1d860bd25c/logs/job/job-logs.txt?rsct=text%2Fplain&se=2026-01-30T23%3A42%3A38Z&sig=l7SeTIKMS1Rbeyf0VQcyb1zCZQ3OYM%2B7dHZLW3ZYOXE%3D&ske=2026-01-31T00%3A51%3A16Z&skoid=ca7593d4-ee42-46cd-af88-8b886a2f84eb&sks=b&skt=2026-01-30T20%3A51%3A16Z&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skv=2025-11-05&sp=r&spr=https&sr=b&st=2026-01-30T23%3A32%3A33Z&sv=2025-11-05.:

2026-01-30T23:25:23.2800918Z   2> java.lang.UnsupportedOperationException: Cannot clean arbitrary ByteBuffer instances
2026-01-30T23:25:23.2801195Z   2> 	at __randomizedtesting.SeedInfo.seed([A1DB2CBBF6757983]:0)
2026-01-30T23:25:23.2801662Z   2> 	at io.netty.util.internal.CleanerJava25.freeDirectBuffer(CleanerJava25.java:183)
2026-01-30T23:25:23.2802245Z   2> 	at io.netty.util.internal.PlatformDependent.freeDirectBuffer(PlatformDependent.java:613)
2026-01-30T23:25:23.2803108Z   2> 	at io.netty.channel.unix.Buffer.free(Buffer.java:36)
2026-01-30T23:25:23.2803767Z   2> 	at io.netty.channel.epoll.EpollEventArray.free(EpollEventArray.java:94)
2026-01-30T23:25:23.2804311Z   2> 	at io.netty.channel.epoll.EpollEventLoop.cleanup(EpollEventLoop.java:540)
2026-01-30T23:25:23.2804993Z   2> 	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1269)
2026-01-30T23:25:23.2827748Z   2> 	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
2026-01-30T23:25:23.2828977Z   2> 	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
2026-01-30T23:25:23.2829893Z   2> 	at java.base/java.lang.Thread.run(Thread.java:1474)
2026-01-30T23:25:23.2830144Z 
2026-01-30T23:25:23.2832372Z   2> com.carrotsearch.randomizedtesting.UncaughtExceptionError: Captured an uncaught exception in thread: Thread[id=265, name=ldaptive-SingleThread@122071539-io-7-1, state=RUNNABLE, group=TGRP-LdapBackendIntegTest2]
2026-01-30T23:25:23.2833391Z         at __randomizedtesting.SeedInfo.seed([A1DB2CBBF6757983:D6934DCC75229F77]:0)
2026-01-30T23:25:23.2833412Z 
2026-01-30T23:25:23.2833627Z         Caused by:
2026-01-30T23:25:23.2834497Z         java.lang.UnsupportedOperationException: Cannot clean arbitrary ByteBuffer instances
2026-01-30T23:25:23.2834958Z             at __randomizedtesting.SeedInfo.seed([A1DB2CBBF6757983]:0)
2026-01-30T23:25:23.2835741Z             at io.netty.util.internal.CleanerJava25.freeDirectBuffer(CleanerJava25.java:183)
2026-01-30T23:25:23.2836711Z             at io.netty.util.internal.PlatformDependent.freeDirectBuffer(PlatformDependent.java:613)
2026-01-30T23:25:23.2837007Z             at io.netty.channel.unix.Buffer.free(Buffer.java:36)
2026-01-30T23:25:23.2837505Z             at io.netty.channel.epoll.EpollEventArray.free(EpollEventArray.java:94)
2026-01-30T23:25:23.2838064Z             at io.netty.channel.epoll.EpollEventLoop.cleanup(EpollEventLoop.java:540)
2026-01-30T23:25:23.2838707Z             at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1269)
2026-01-30T23:25:23.2839121Z             at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
2026-01-30T23:25:23.2839679Z             at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
2026-01-30T23:25:23.2839970Z             at java.base/java.lang.Thread.run(Thread.java:1474)

retry {
failOnPassedAfterRetry = false
maxRetries = 5
Expand Down Expand Up @@ -680,7 +686,7 @@ dependencies {
implementation "org.bouncycastle:bc-fips:${versions.bouncycastle_jce}"
implementation "org.bouncycastle:bcpkix-fips:${versions.bouncycastle_pkix}"
implementation "org.bouncycastle:bcutil-fips:${versions.bouncycastle_util}"
implementation 'org.ldaptive:ldaptive:1.2.3'
implementation 'org.ldaptive:ldaptive:2.3.2'
implementation 'com.nimbusds:nimbus-jose-jwt:10.7'
implementation 'com.rfksystems:blake2b:2.0.0'
implementation "com.password4j:password4j:${versions.password4j}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,11 @@
import org.opensearch.security.support.WildcardMatcher;
import org.opensearch.security.user.User;

import org.ldaptive.Connection;
import org.ldaptive.ConnectionConfig;
import org.ldaptive.ConnectionFactory;
import org.ldaptive.FilterTemplate;
import org.ldaptive.LdapAttribute;
import org.ldaptive.LdapEntry;
import org.ldaptive.ReturnAttributes;
import org.ldaptive.SearchFilter;
import org.ldaptive.SearchScope;

import static org.opensearch.security.setting.DeprecatedSettings.checkForDeprecatedSetting;
Expand Down Expand Up @@ -87,19 +86,18 @@ public LDAPAuthenticationBackend(final Settings settings, final Path configPath)
@Override
public User authenticate(AuthenticationContext context) throws OpenSearchSecurityException {

Connection ldapConnection = null;
ConnectionFactory connectionFactory = null;
final String user = context.getCredentials().getUsername();
byte[] password = context.getCredentials().getPassword();

try {
LdapEntry entry;
String dn;
ConnectionConfig connectionConfig;

try {
ldapConnection = LDAPAuthorizationBackend.getConnection(settings, configPath);
connectionFactory = LDAPAuthorizationBackend.getConnectionFactory(settings, configPath);

entry = exists(user, ldapConnection, settings, userBaseSettings, this.returnAttributes, this.shouldFollowReferrals);
entry = exists(user, connectionFactory, settings, userBaseSettings, this.returnAttributes, this.shouldFollowReferrals);

// fake a user that no exists
// makes guessing if a user exists or not harder when looking on the
Expand All @@ -109,7 +107,7 @@ public User authenticate(AuthenticationContext context) throws OpenSearchSecurit
ConfigConstants.LDAP_FAKE_LOGIN_DN,
"CN=faketomakebindfail,DC=" + UUID.randomUUID().toString()
);
entry = new LdapEntry(fakeLognDn);
entry = LdapEntry.builder().dn(fakeLognDn).build();
password = settings.get(ConfigConstants.LDAP_FAKE_LOGIN_PASSWORD, "fakeLoginPwd123").getBytes(StandardCharsets.UTF_8);
} else if (entry == null) {
throw new OpenSearchSecurityException("No user " + user + " found");
Expand All @@ -121,12 +119,11 @@ public User authenticate(AuthenticationContext context) throws OpenSearchSecurit
log.trace("Try to authenticate dn {}", dn);
}

connectionConfig = ldapConnection.getConnectionConfig();
} finally {
Utils.unbindAndCloseSilently(ldapConnection);
closeConnectionFactory(connectionFactory);
}

LDAPAuthorizationBackend.checkConnection(connectionConfig, dn, password);
LDAPAuthorizationBackend.checkConnection(settings, configPath, dn, password);

final String usernameAttribute = settings.get(ConfigConstants.LDAP_AUTHC_USERNAME_ATTRIBUTE, null);
String username = dn;
Expand Down Expand Up @@ -161,7 +158,7 @@ public User authenticate(AuthenticationContext context) throws OpenSearchSecurit
} finally {
Arrays.fill(password, (byte) '\0');
password = null;
Utils.unbindAndCloseSilently(ldapConnection);
closeConnectionFactory(connectionFactory);
}

}
Expand All @@ -173,14 +170,14 @@ public String getType() {

@Override
public Optional<User> impersonate(User user) {
Connection ldapConnection = null;
ConnectionFactory connectionFactory = null;
String userName = user.getName();

try {
ldapConnection = LDAPAuthorizationBackend.getConnection(settings, configPath);
connectionFactory = LDAPAuthorizationBackend.getConnectionFactory(settings, configPath);
LdapEntry userEntry = exists(
userName,
ldapConnection,
connectionFactory,
settings,
userBaseSettings,
this.returnAttributes,
Expand All @@ -198,7 +195,7 @@ public Optional<User> impersonate(User user) {
log.warn("User {} does not exist due to exception", userName, e);
return Optional.empty();
} finally {
Utils.unbindAndCloseSilently(ldapConnection);
closeConnectionFactory(connectionFactory);
}
}

Expand Down Expand Up @@ -227,7 +224,7 @@ static List<Map.Entry<String, Settings>> getUserBaseSettings(Settings settings)

static LdapEntry exists(
final String user,
Connection ldapConnection,
ConnectionFactory connectionFactory,
Settings settings,
List<Map.Entry<String, Settings>> userBaseSettings,
String[] returnAttributes,
Expand All @@ -236,16 +233,16 @@ static LdapEntry exists(
if (settings.getAsBoolean(ConfigConstants.LDAP_FAKE_LOGIN_ENABLED, false)
|| settings.getAsBoolean(ConfigConstants.LDAP_SEARCH_ALL_BASES, false)
|| settings.hasValue(ConfigConstants.LDAP_AUTHC_USERBASE)) {
return existsSearchingAllBases(user, ldapConnection, userBaseSettings, returnAttributes, shouldFollowReferrals);
return existsSearchingAllBases(user, connectionFactory, userBaseSettings, returnAttributes, shouldFollowReferrals);
} else {
return existsSearchingUntilFirstHit(user, ldapConnection, userBaseSettings, returnAttributes, shouldFollowReferrals);
return existsSearchingUntilFirstHit(user, connectionFactory, userBaseSettings, returnAttributes, shouldFollowReferrals);
}

}

private static LdapEntry existsSearchingUntilFirstHit(
final String user,
Connection ldapConnection,
ConnectionFactory connectionFactory,
List<Map.Entry<String, Settings>> userBaseSettings,
final String[] returnAttributes,
final boolean shouldFollowReferrals
Expand All @@ -256,14 +253,15 @@ private static LdapEntry existsSearchingUntilFirstHit(
for (Map.Entry<String, Settings> entry : userBaseSettings) {
Settings baseSettings = entry.getValue();

SearchFilter f = new SearchFilter();
f.setFilter(baseSettings.get(ConfigConstants.LDAP_AUTHCZ_SEARCH, DEFAULT_USERSEARCH_PATTERN));
f.setParameter(ZERO_PLACEHOLDER, username);
FilterTemplate filter = FilterTemplate.builder()
.filter(baseSettings.get(ConfigConstants.LDAP_AUTHCZ_SEARCH, DEFAULT_USERSEARCH_PATTERN))
.parameters(username)
.build();

List<LdapEntry> result = LdapHelper.search(
ldapConnection,
connectionFactory,
baseSettings.get(ConfigConstants.LDAP_AUTHCZ_BASE, DEFAULT_USERBASE),
f,
filter,
SearchScope.SUBTREE,
returnAttributes,
shouldFollowReferrals
Expand All @@ -283,7 +281,7 @@ private static LdapEntry existsSearchingUntilFirstHit(

private static LdapEntry existsSearchingAllBases(
final String user,
Connection ldapConnection,
ConnectionFactory connectionFactory,
List<Map.Entry<String, Settings>> userBaseSettings,
final String[] returnAttributes,
final boolean shouldFollowReferrals
Expand All @@ -295,14 +293,15 @@ private static LdapEntry existsSearchingAllBases(
for (Map.Entry<String, Settings> entry : userBaseSettings) {
Settings baseSettings = entry.getValue();

SearchFilter f = new SearchFilter();
f.setFilter(baseSettings.get(ConfigConstants.LDAP_AUTHCZ_SEARCH, DEFAULT_USERSEARCH_PATTERN));
f.setParameter(ZERO_PLACEHOLDER, username);
FilterTemplate filter = FilterTemplate.builder()
.filter(baseSettings.get(ConfigConstants.LDAP_AUTHCZ_SEARCH, DEFAULT_USERSEARCH_PATTERN))
.parameters(username)
.build();

List<LdapEntry> foundEntries = LdapHelper.search(
ldapConnection,
connectionFactory,
baseSettings.get(ConfigConstants.LDAP_AUTHCZ_BASE, DEFAULT_USERBASE),
f,
filter,
SearchScope.SUBTREE,
returnAttributes,
shouldFollowReferrals
Expand Down Expand Up @@ -367,4 +366,14 @@ public static ImmutableMap<String, String> extractLdapAttributes(
}
return attributes.build();
}

private static void closeConnectionFactory(ConnectionFactory connectionFactory) {
if (connectionFactory instanceof AutoCloseable) {
try {
((AutoCloseable) connectionFactory).close();
} catch (Exception e) {
// ignore
}
}
}
}
Loading
Loading