Use cache for password hash while validating LDAP password (#15993)

This commit is contained in:
Kashif Faraz 2024-02-28 18:33:33 +05:30 committed by GitHub
parent d2c2036ea2
commit f757231420
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 28 additions and 33 deletions

View File

@ -92,9 +92,9 @@ public class LdapUserPrincipal implements Principal
return lastVerified.get();
}
public boolean hasSameCredentials(char[] password)
public boolean hasSameCredentials(char[] password, PasswordHashGenerator hashGenerator)
{
byte[] recalculatedHash = PasswordHashGenerator.computePasswordHash(
byte[] recalculatedHash = hashGenerator.getOrComputePasswordHash(
password,
this.credentials.getSalt(),
this.credentials.getIterations()

View File

@ -153,14 +153,13 @@ public class LDAPCredentialsValidator implements CredentialsValidator
char[] password
)
{
SearchResult userResult;
LdapName userDn;
Map<String, Object> contextMap = new HashMap<>();
final SearchResult userResult;
final LdapName userDn;
final Map<String, Object> contextMap = new HashMap<>();
final LdapUserPrincipal principal = this.cache.getOrExpire(username);
LdapUserPrincipal principal = this.cache.getOrExpire(username);
if (principal != null && principal.hasSameCredentials(password)) {
if (principal != null && principal.hasSameCredentials(password, hashGenerator)) {
contextMap.put(BasicAuthUtils.SEARCH_RESULT_CONTEXT_KEY, principal.getSearchResult());
return new AuthenticationResult(username, authorizerName, authenticatorName, contextMap);
} else {
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
@ -208,8 +207,8 @@ public class LDAPCredentialsValidator implements CredentialsValidator
this.cache.put(username, newPrincipal);
contextMap.put(BasicAuthUtils.SEARCH_RESULT_CONTEXT_KEY, userResult);
return new AuthenticationResult(username, authorizerName, authenticatorName, contextMap);
}
return new AuthenticationResult(username, authorizerName, authenticatorName, contextMap);
}
/**

View File

@ -36,7 +36,6 @@ import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapContext;
import javax.naming.spi.InitialContextFactory;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
@ -94,6 +93,7 @@ public class LDAPCredentialsValidatorTest
properties
);
validator.validateCredentials("ldap", "ldap", "validUser", "password".toCharArray());
validator.validateCredentials("ldap", "ldap", "validUser", "password".toCharArray());
}
public static class MockContextFactory implements InitialContextFactory

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.apache.druid.security.authentication.validator;
package org.apache.druid.security.basic.authentication.validator;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Provider;
@ -28,28 +28,21 @@ import org.apache.druid.security.basic.authentication.db.cache.BasicAuthenticato
import org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorCredentialUpdate;
import org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorCredentials;
import org.apache.druid.security.basic.authentication.entity.BasicAuthenticatorUser;
import org.apache.druid.security.basic.authentication.validator.MetadataStoreCredentialsValidator;
import org.apache.druid.server.security.Access;
import org.apache.druid.server.security.AuthenticationResult;
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.Map;
public class DBCredentialsValidatorTest
public class MetadataStoreCredentialsValidatorTest
{
@Rule
public ExpectedException expectedException = ExpectedException.none();
private static BasicAuthenticatorCredentials USER_A_CREDENTIALS = new BasicAuthenticatorCredentials(
private static final BasicAuthenticatorCredentials USER_A_CREDENTIALS = new BasicAuthenticatorCredentials(
new BasicAuthenticatorCredentialUpdate("helloworld", 20)
);
private static Provider<BasicAuthenticatorCacheManager> CACHE_MANAGER_PROVIDER = Providers.of(
private static final Provider<BasicAuthenticatorCacheManager> CACHE_MANAGER_PROVIDER = Providers.of(
new BasicAuthenticatorCacheManager()
{
@Override
@ -69,9 +62,8 @@ public class DBCredentialsValidatorTest
}
);
private static MetadataStoreCredentialsValidator validator = new MetadataStoreCredentialsValidator(CACHE_MANAGER_PROVIDER);
private static final MetadataStoreCredentialsValidator VALIDATOR
= new MetadataStoreCredentialsValidator(CACHE_MANAGER_PROVIDER);
@Test
public void validateBadAuthenticator()
@ -87,9 +79,11 @@ public class DBCredentialsValidatorTest
MetadataStoreCredentialsValidator validator = new MetadataStoreCredentialsValidator(Providers.of(cacheManager));
expectedException.expect(IAE.class);
expectedException.expectMessage("No userMap is available for authenticator with prefix: [notbasic]");
validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
IAE exception = Assert.assertThrows(
IAE.class,
() -> validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray())
);
Assert.assertEquals("No userMap is available for authenticator with prefix: [notbasic]", exception.getMessage());
EasyMock.verify(cacheManager);
}
@ -102,7 +96,7 @@ public class DBCredentialsValidatorTest
String username = "userB";
String password = "helloworld";
AuthenticationResult result = validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
AuthenticationResult result = VALIDATOR.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
Assert.assertNull(result);
}
@ -114,7 +108,7 @@ public class DBCredentialsValidatorTest
String username = "userC";
String password = "helloworld";
AuthenticationResult result = validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
AuthenticationResult result = VALIDATOR.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
Assert.assertNull(result);
}
@ -126,7 +120,7 @@ public class DBCredentialsValidatorTest
String username = "userA";
String password = "helloworld";
AuthenticationResult result = validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
AuthenticationResult result = VALIDATOR.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
Assert.assertNotNull(result);
Assert.assertEquals(username, result.getIdentity());
@ -143,8 +137,10 @@ public class DBCredentialsValidatorTest
String username = "userA";
String password = "badpassword";
expectedException.expect(BasicSecurityAuthenticationException.class);
expectedException.expectMessage(Access.DEFAULT_ERROR_MESSAGE);
validator.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray());
Exception exception = Assert.assertThrows(
BasicSecurityAuthenticationException.class,
() -> VALIDATOR.validateCredentials(authenticatorName, authorizerName, username, password.toCharArray())
);
Assert.assertEquals(Access.DEFAULT_ERROR_MESSAGE, exception.getMessage());
}
}