From 69cf04dcbf2bb1c99870f63ddccb9840b37f4f04 Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Tue, 25 Mar 2025 14:11:41 +0100 Subject: [PATCH 1/6] Made user object immutable Signed-off-by: Nils Bandener --- CHANGELOG.md | 2 + .../privileges/ActionPrivilegesTest.java | 6 +- .../security/privileges/IndexPatternTest.java | 5 +- .../dlsfls/DocumentPrivilegesTest.java | 4 +- .../opensearch/security/user/UserTest.java | 54 ++++ .../com/amazon/dlic/auth/ldap/LdapUser.java | 7 +- .../security/OpenSearchSecurityPlugin.java | 8 +- .../auditlog/impl/AbstractAuditLog.java | 8 +- .../security/auditlog/impl/AuditLogImpl.java | 11 +- .../security/auth/AuthenticationBackend.java | 10 - .../security/auth/AuthorizationBackend.java | 2 +- .../security/auth/BackendRegistry.java | 57 ++-- .../security/auth/ImpersonationBackend.java | 33 +++ .../security/auth/RolesInjector.java | 6 +- .../security/auth/UserInjector.java | 113 ++++---- .../InternalAuthenticationBackend.java | 82 +++--- .../internal/NoOpAuthenticationBackend.java | 21 +- .../internal/NoOpAuthorizationBackend.java | 5 +- .../backend/LDAPAuthenticationBackend.java | 24 +- .../backend/LDAPAuthorizationBackend.java | 17 +- .../ldap2/LDAPAuthenticationBackend2.java | 66 +++-- .../auth/ldap2/LDAPAuthorizationBackend2.java | 26 +- .../security/filter/SecurityFilter.java | 8 +- .../privileges/PrivilegesEvaluator.java | 2 - .../security/rest/SecurityInfoAction.java | 7 +- .../security/securityconf/ConfigModelV7.java | 5 +- .../securityconf/DynamicConfigFactory.java | 17 +- .../securityconf/InternalUsersModel.java | 10 +- .../security/support/Base64Helper.java | 7 +- .../support/SafeSerializationUtils.java | 7 +- .../transport/SecurityInterceptor.java | 11 +- .../transport/SecurityRequestHandler.java | 10 +- .../security/user/AuthCredentials.java | 16 +- .../org/opensearch/security/user/User.java | 245 ++++++++++++------ .../opensearch/security/user/UserFactory.java | 56 ++++ .../security/user/serialized/User.java | 69 +++++ .../auth/InternalAuthBackendTests.java | 8 +- .../security/auth/UserInjectorTest.java | 27 +- .../security/auth/ldap/LdapBackendTest.java | 131 ++++------ .../ldap/LdapBackendTestNewStyleConfig.java | 90 +++---- .../ldap2/LdapBackendTestNewStyleConfig2.java | 138 +++++----- .../ldap2/LdapBackendTestOldStyleConfig2.java | 124 ++++----- .../cache/DummyAuthenticationBackend.java | 9 +- .../security/cache/DummyAuthorizer.java | 5 +- .../SystemIndexAccessEvaluatorTest.java | 3 +- .../security/support/Base64HelperTest.java | 30 --- .../support/SafeSerializationUtilsTest.java | 2 - .../transport/SecurityInterceptorTests.java | 4 +- 48 files changed, 905 insertions(+), 703 deletions(-) create mode 100644 src/integrationTest/java/org/opensearch/security/user/UserTest.java create mode 100644 src/main/java/org/opensearch/security/auth/ImpersonationBackend.java create mode 100644 src/main/java/org/opensearch/security/user/UserFactory.java create mode 100644 src/main/java/org/opensearch/security/user/serialized/User.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0372bbd943..ab3e45cc7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed - Use extendedPlugins in integrationTest framework for sample resource plugin testing ([#5322](https://github.com/opensearch-project/security/pull/5322)) +- Performance improvements: Immutable user object ([#5212]) + ### Dependencies - Bump `guava_version` from 33.4.6-jre to 33.4.8-jre ([#5284](https://github.com/opensearch-project/security/pull/5284)) - Bump `spring_version` from 6.2.5 to 6.2.6 ([#5283](https://github.com/opensearch-project/security/pull/5283)) diff --git a/src/integrationTest/java/org/opensearch/security/privileges/ActionPrivilegesTest.java b/src/integrationTest/java/org/opensearch/security/privileges/ActionPrivilegesTest.java index 8618e27306..e2830246da 100644 --- a/src/integrationTest/java/org/opensearch/security/privileges/ActionPrivilegesTest.java +++ b/src/integrationTest/java/org/opensearch/security/privileges/ActionPrivilegesTest.java @@ -1071,8 +1071,7 @@ static SecurityDynamicConfiguration createRoles(int numberOfRoles, int n } static PrivilegesEvaluationContext ctx(String... roles) { - User user = new User("test_user"); - user.addAttributes(ImmutableMap.of("attrs.dept_no", "a11")); + User user = new User("test_user").withAttributes(ImmutableMap.of("attrs.dept_no", "a11")); return new PrivilegesEvaluationContext( user, ImmutableSet.copyOf(roles), @@ -1086,8 +1085,7 @@ static PrivilegesEvaluationContext ctx(String... roles) { } static PrivilegesEvaluationContext ctxByUsername(String username) { - User user = new User(username); - user.addAttributes(ImmutableMap.of("attrs.dept_no", "a11")); + User user = new User(username).withAttributes(ImmutableMap.of("attrs.dept_no", "a11")); return new PrivilegesEvaluationContext( user, ImmutableSet.of(), diff --git a/src/integrationTest/java/org/opensearch/security/privileges/IndexPatternTest.java b/src/integrationTest/java/org/opensearch/security/privileges/IndexPatternTest.java index e098a605e5..cc6766c2ea 100644 --- a/src/integrationTest/java/org/opensearch/security/privileges/IndexPatternTest.java +++ b/src/integrationTest/java/org/opensearch/security/privileges/IndexPatternTest.java @@ -234,10 +234,7 @@ public void equals() { private static PrivilegesEvaluationContext ctx() { IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(new ThreadContext(Settings.EMPTY)); IndexResolverReplacer indexResolverReplacer = new IndexResolverReplacer(indexNameExpressionResolver, () -> CLUSTER_STATE, null); - User user = new User("test_user"); - user.addAttributes(ImmutableMap.of("attrs.a11", "a11")); - user.addAttributes(ImmutableMap.of("attrs.year", "year")); - + User user = new User("test_user").withAttributes(ImmutableMap.of("attrs.a11", "a11", "attrs.year", "year")); return new PrivilegesEvaluationContext( user, ImmutableSet.of(), diff --git a/src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java b/src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java index 97a0ddb69e..1ffa4e7ad8 100644 --- a/src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java +++ b/src/integrationTest/java/org/opensearch/security/privileges/dlsfls/DocumentPrivilegesTest.java @@ -1191,9 +1191,7 @@ UserSpec attribute(String name, String value) { } User buildUser() { - User user = new User("test_user_" + description); - user.addAttributes(this.attributes); - return user; + return new User("test_user_" + description).withAttributes(this.attributes); } @Override diff --git a/src/integrationTest/java/org/opensearch/security/user/UserTest.java b/src/integrationTest/java/org/opensearch/security/user/UserTest.java new file mode 100644 index 0000000000..2e9ed0ab77 --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/user/UserTest.java @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ +package org.opensearch.security.user; + +import java.util.Arrays; + +import com.google.common.collect.ImmutableMap; +import org.junit.Test; + +import org.opensearch.security.support.Base64Helper; + +import static org.junit.Assert.assertEquals; + +public class UserTest { + @Test + public void serialization() { + User user = new User("serialization_test_user").withRoles(Arrays.asList("br1", "br2", "br3")) + .withSecurityRoles(Arrays.asList("sr1", "sr2")) + .withAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")); + + String serialized = Base64Helper.serializeObject(user); + User user2 = User.fromSerializedBase64(serialized); + assertEquals(user, user2); + + } + + @Test + public void deserializationFrom2_19() { + // The following base64 string was produced by the following code on OpenSearch 2.19 + // User user = new User("serialization_test_user"); + // user.addRoles(Arrays.asList("br1", "br2", "br3")); + // user.addSecurityRoles(Arrays.asList("sr1", "sr2")); + // user.addAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")); + // System.out.println(Base64JDKHelper.serializeObject(user)); + String serialized = + "rO0ABXNyACFvcmcub3BlbnNlYXJjaC5zZWN1cml0eS51c2VyLlVzZXKzqL2T65dH3AIABloACmlzSW5qZWN0ZWRMAAphdHRyaWJ1dGVzdAAPTGphdmEvdXRpbC9NYXA7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAD3JlcXVlc3RlZFRlbmFudHEAfgACTAAFcm9sZXN0AA9MamF2YS91dGlsL1NldDtMAA1zZWN1cml0eVJvbGVzcQB+AAN4cABzcgAlamF2YS51dGlsLkNvbGxlY3Rpb25zJFN5bmNocm9uaXplZE1hcBtz+QlLSzl7AwACTAABbXEAfgABTAAFbXV0ZXh0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAN3CAAAAAQAAAACdAABYXQAA3ZfYXQAAWJ0AAN2X2J4cQB+AAd4dAAXc2VyaWFsaXphdGlvbl90ZXN0X3VzZXJwc3IAJWphdmEudXRpbC5Db2xsZWN0aW9ucyRTeW5jaHJvbml6ZWRTZXQGw8J5Au7fPAIAAHhyACxqYXZhLnV0aWwuQ29sbGVjdGlvbnMkU3luY2hyb25pemVkQ29sbGVjdGlvbiph+E0JnJm1AwACTAABY3QAFkxqYXZhL3V0aWwvQ29sbGVjdGlvbjtMAAVtdXRleHEAfgAGeHBzcgARamF2YS51dGlsLkhhc2hTZXS6RIWVlri3NAMAAHhwdwwAAAAQP0AAAAAAAAN0AANicjF0AANicjN0AANicjJ4cQB+ABJ4c3EAfgAPc3EAfgATdwwAAAAQP0AAAAAAAAJ0AANzcjJ0AANzcjF4cQB+ABh4"; + + User user = User.fromSerializedBase64(serialized); + assertEquals( + new User("serialization_test_user").withRoles(Arrays.asList("br1", "br2", "br3")) + .withSecurityRoles(Arrays.asList("sr1", "sr2")) + .withAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")), + user + ); + } +} diff --git a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java index 58c4dfda5d..47e42e282f 100755 --- a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java +++ b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java @@ -15,6 +15,10 @@ import java.util.HashMap; import java.util.Map; +import com.google.common.collect.ImmutableSet; + +import org.opensearch.core.common.io.stream.StreamInput; +import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.security.auth.ldap.util.Utils; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.user.AuthCredentials; @@ -48,10 +52,11 @@ public LdapUser( int customAttrMaxValueLen, WildcardMatcher allowlistedCustomLdapAttrMatcher ) { - super(name, null, credentials); + super(name, ImmutableSet.of(), credentials); this.originalUsername = originalUsername; this.userEntry = userEntry; Map attributes = getCustomAttributesMap(); + // TODO attributes.putAll(extractLdapAttributes(originalUsername, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher)); } diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 6eb4268f41..084e3b2f32 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -213,6 +213,7 @@ import org.opensearch.security.transport.InterClusterRequestEvaluator; import org.opensearch.security.transport.SecurityInterceptor; import org.opensearch.security.user.User; +import org.opensearch.security.user.UserFactory; import org.opensearch.security.user.UserService; import org.opensearch.tasks.Task; import org.opensearch.telemetry.tracing.Tracer; @@ -1118,6 +1119,8 @@ public Collection createComponents( interClusterRequestEvaluator = ReflectionHelper.instantiateInterClusterRequestEvaluator(className, settings); } + UserFactory userFactory = new UserFactory.Caching(); + final PrivilegesInterceptor privilegesInterceptor; namedXContentRegistry.set(xContentRegistry); @@ -1125,7 +1128,7 @@ public Collection createComponents( auditLog = new NullAuditLog(); privilegesInterceptor = new PrivilegesInterceptor(resolver, clusterService, localClient, threadPool); } else { - auditLog = new AuditLogImpl(settings, configPath, localClient, threadPool, resolver, clusterService, environment); + auditLog = new AuditLogImpl(settings, configPath, localClient, threadPool, resolver, clusterService, environment, userFactory); privilegesInterceptor = new PrivilegesInterceptorImpl(resolver, clusterService, localClient, threadPool); } @@ -1226,7 +1229,8 @@ public Collection createComponents( Objects.requireNonNull(sslExceptionHandler), Objects.requireNonNull(cih), SSLConfig, - OpenSearchSecurityPlugin::isActionTraceEnabled + OpenSearchSecurityPlugin::isActionTraceEnabled, + userFactory ); components.add(principalExtractor); diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 65094ac94d..34d0a0ba29 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -74,6 +74,7 @@ import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; +import org.opensearch.security.user.UserFactory; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; @@ -96,6 +97,7 @@ public abstract class AbstractAuditLog implements AuditLog { private final Environment environment; private AtomicBoolean externalConfigLogged = new AtomicBoolean(); private final Set ignoredUrlParams = new HashSet<>(); + private final UserFactory userFactory; protected abstract void enableRoutes(); @@ -113,7 +115,8 @@ protected AbstractAuditLog( final ThreadPool threadPool, final IndexNameExpressionResolver resolver, final ClusterService clusterService, - final Environment environment + final Environment environment, + final UserFactory userFactory ) { super(); this.threadPool = threadPool; @@ -125,6 +128,7 @@ protected AbstractAuditLog( ConfigConstants.OPENDISTRO_SECURITY_DEFAULT_CONFIG_INDEX ); this.environment = environment; + this.userFactory = userFactory; } protected void onAuditConfigFilterChanged(AuditConfig.Filter auditConfigFilter) { @@ -785,7 +789,7 @@ private TransportAddress getRemoteAddress() { private String getUser() { User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); if (user == null && threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER) != null) { - user = (User) Base64Helper.deserializeObject( + user = this.userFactory.fromSerializedBase64( threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER) ); } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java index a5b4af9418..709e6b1582 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AuditLogImpl.java @@ -31,6 +31,7 @@ import org.opensearch.security.auditlog.config.AuditConfig; import org.opensearch.security.auditlog.routing.AuditMessageRouter; import org.opensearch.security.filter.SecurityRequest; +import org.opensearch.security.user.UserFactory; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; @@ -46,6 +47,9 @@ public final class AuditLogImpl extends AbstractAuditLog { private volatile boolean enabled; private final Thread shutdownHook; + /** + * Only used for testing. + */ public AuditLogImpl( final Settings settings, final Path configPath, @@ -54,7 +58,7 @@ public AuditLogImpl( final IndexNameExpressionResolver resolver, final ClusterService clusterService ) { - this(settings, configPath, clientProvider, threadPool, resolver, clusterService, null); + this(settings, configPath, clientProvider, threadPool, resolver, clusterService, null, new UserFactory.Simple()); } @SuppressWarnings("removal") @@ -65,9 +69,10 @@ public AuditLogImpl( final ThreadPool threadPool, final IndexNameExpressionResolver resolver, final ClusterService clusterService, - final Environment environment + final Environment environment, + final UserFactory userFactory ) { - super(settings, threadPool, resolver, clusterService, environment); + super(settings, threadPool, resolver, clusterService, environment, userFactory); this.settings = settings; this.messageRouter = new AuditMessageRouter(settings, clientProvider, threadPool, configPath, clusterService); this.messageRouterEnabled = this.messageRouter.isEnabled(); diff --git a/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java index 0296f56a4a..3d78826614 100644 --- a/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java @@ -66,14 +66,4 @@ public interface AuthenticationBackend { */ User authenticate(AuthCredentials credentials) throws OpenSearchSecurityException; - /** - * - * Lookup for a specific user in the authentication backend - * - * @param user The user for which the authentication backend should be queried. If the authentication backend supports - * user attributes in combination with impersonation the attributes needs to be added to user by calling {@code user.addAttributes()} - * @return true if the user exists in the authentication backend, false otherwise. Before return call {@code user.addAttributes()} as explained above. - */ - boolean exists(User user); - } diff --git a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java index 3aea412e69..42813aed58 100644 --- a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java @@ -65,6 +65,6 @@ public interface AuthorizationBackend { * @throws OpenSearchSecurityException in case when the authorization backend cannot be reached * or the {@code credentials} are insufficient to authenticate to the authorization backend. */ - void fillRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException; + User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException; } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index 340f7a955d..f5b620ffe4 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -395,7 +395,10 @@ public boolean authenticate(final SecurityRequestChannel request) { log.debug("securitytenant '{}'", tenant); } - authenticatedUser.setRequestedTenant(tenant); + if (tenant != null) { + authenticatedUser = authenticatedUser.withRequestedTenant(tenant); + } + authenticated = true; break; }// end looping auth domains @@ -430,9 +433,12 @@ public boolean authenticate(final SecurityRequestChannel request) { } if (authCredentials == null && anonymousAuthEnabled && isRequestForAnonymousLogin(request.params(), request.getHeaders())) { + User anonymousUser = User.ANONYMOUS; + final String tenant = resolveTenantFrom(request); - User anonymousUser = new User(User.ANONYMOUS.getName(), new HashSet(User.ANONYMOUS.getRoles()), null); - anonymousUser.setRequestedTenant(tenant); + if (tenant != null) { + anonymousUser = anonymousUser.withRequestedTenant(tenant); + } UserSubject subject = new UserSubjectImpl(threadPool, anonymousUser); @@ -498,7 +504,7 @@ private void notifyIpAuthFailureListeners(InetAddress remoteAddress, AuthCredent private User checkExistsAndAuthz( final Cache cache, final User user, - final AuthenticationBackend authenticationBackend, + final ImpersonationBackend impersonationBackend, final Set authorizers ) { if (user == null) { @@ -516,16 +522,17 @@ public User call() throws Exception { log.trace( "Credentials for user {} not cached, return from {} backend directly", user.getName(), - authenticationBackend.getType() + impersonationBackend.getType() ); } - if (authenticationBackend.exists(user)) { - authz(user, null, authorizers); // no role cache because no miss here in case of noop - return user; + + Optional impersonatedUser = impersonationBackend.impersonate(user); + if (impersonatedUser.isPresent()) { + return authz(impersonatedUser.get(), null, authorizers); // no role cache because no miss here in case of noop } if (isDebugEnabled) { - log.debug("User {} does not exist in {}", user.getName(), authenticationBackend.getType()); + log.debug("User {} does not exist in {}", user.getName(), impersonationBackend.getType()); } return null; } @@ -538,10 +545,10 @@ public User call() throws Exception { } } - private void authz(User authenticatedUser, Cache> roleCache, final Set authorizers) { + private User authz(User authenticatedUser, Cache> roleCache, final Set authorizers) { if (authenticatedUser == null) { - return; + return authenticatedUser; } if (roleCache != null) { @@ -549,13 +556,12 @@ private void authz(User authenticatedUser, Cache> roleCache, f final Set cachedBackendRoles = roleCache.getIfPresent(authenticatedUser); if (cachedBackendRoles != null) { - authenticatedUser.addRoles(new HashSet(cachedBackendRoles)); - return; + return authenticatedUser.withRoles(cachedBackendRoles); } } if (authorizers == null || authorizers.isEmpty()) { - return; + return authenticatedUser; } final boolean isTraceEnabled = log.isTraceEnabled(); @@ -568,7 +574,8 @@ private void authz(User authenticatedUser, Cache> roleCache, f ab.getType() ); } - ab.fillRoles(authenticatedUser, new AuthCredentials(authenticatedUser.getName())); + + authenticatedUser = ab.addRoles(authenticatedUser, new AuthCredentials(authenticatedUser.getName())); } catch (Exception e) { log.error("Cannot retrieve roles for {} from {} due to {}", authenticatedUser, ab.getType(), e.toString(), e); } @@ -577,6 +584,8 @@ private void authz(User authenticatedUser, Cache> roleCache, f if (roleCache != null) { roleCache.put(authenticatedUser, new HashSet(authenticatedUser.getRoles())); } + + return authenticatedUser; } /** @@ -614,8 +623,7 @@ public User call() throws Exception { ); } final User authenticatedUser = authBackend.authenticate(ac); - authz(authenticatedUser, roleCache, authorizers); - return authenticatedUser; + return authz(authenticatedUser, roleCache, authorizers); } }); } catch (Exception e) { @@ -656,16 +664,18 @@ private User impersonate(final SecurityRequest request, final User originalUser) final boolean isDebugEnabled = log.isDebugEnabled(); // loop over all http/rest auth domains for (final AuthDomain authDomain : restAuthDomains) { - final AuthenticationBackend authenticationBackend = authDomain.getBackend(); + if (!(authDomain.getBackend() instanceof ImpersonationBackend impersonationBackend)) { + continue; + } if (!authDomain.getHttpAuthenticator().supportsImpersonation()) { continue; } - final User impersonatedUser = checkExistsAndAuthz( + User impersonatedUser = checkExistsAndAuthz( restImpersonationCache, new User(impersonatedUserHeader), - authenticationBackend, + impersonationBackend, restAuthorizers ); @@ -674,7 +684,7 @@ private User impersonate(final SecurityRequest request, final User originalUser) "Unable to impersonate rest user from '{}' to '{}' because the impersonated user does not exists in {}, try next ...", originalUser.getName(), impersonatedUserHeader, - authenticationBackend.getType() + impersonationBackend.getType() ); continue; } @@ -687,7 +697,10 @@ private User impersonate(final SecurityRequest request, final User originalUser) ); } - impersonatedUser.setRequestedTenant(originalUser.getRequestedTenant()); + if (originalUser.getRequestedTenant() != null) { + impersonatedUser = impersonatedUser.withRequestedTenant(originalUser.getRequestedTenant()); + } + return impersonatedUser; } diff --git a/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java b/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java new file mode 100644 index 0000000000..5624d36969 --- /dev/null +++ b/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java @@ -0,0 +1,33 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.auth; + +import java.util.Optional; + +import org.opensearch.security.user.User; + +public interface ImpersonationBackend { + /** + * The type (name) of the impersonation backend. Only for logging. + */ + String getType(); + + /** + * Completes a user object based on information in an authentication backend. This is used to perform user impersonation. + * + * @param user The user for which the authentication backend should be queried. If the authentication backend supports + * user attributes in combination with impersonation the attributes needs to be added to user which is returned by this method. + * + * @return An Optional. If the user is found, Optional.isPresent() returns true, otherwise it returns false. + */ + Optional impersonate(User user); +} diff --git a/src/main/java/org/opensearch/security/auth/RolesInjector.java b/src/main/java/org/opensearch/security/auth/RolesInjector.java index 6c0eaa0732..4512610bd1 100644 --- a/src/main/java/org/opensearch/security/auth/RolesInjector.java +++ b/src/main/java/org/opensearch/security/auth/RolesInjector.java @@ -65,17 +65,15 @@ public Set injectUserAndRoles(TransportRequest transportRequest, String log.error("Username must be provided, injected string was '{}.' Roles injection failed.", injectedUserAndRoles); return null; } - User user = new User(strs[0]); if (strs.length < 2 || StringUtils.isEmpty(StringUtils.trim(strs[0]))) { log.error("Roles must be provided, injected string was '{}.' Roles injection failed.", injectedUserAndRoles); return null; } Set roles = ImmutableSet.copyOf(strs[1].split(",")); + User user = new User(strs[0]).withSecurityRoles(roles); - if (user != null && roles != null) { - addUser(user, transportRequest, action, task, ctx); - } + addUser(user, transportRequest, action, task, ctx); return roles; } diff --git a/src/main/java/org/opensearch/security/auth/UserInjector.java b/src/main/java/org/opensearch/security/auth/UserInjector.java index 1e775d6e33..f3a0470749 100644 --- a/src/main/java/org/opensearch/security/auth/UserInjector.java +++ b/src/main/java/org/opensearch/security/auth/UserInjector.java @@ -26,7 +26,6 @@ package org.opensearch.security.auth; -import java.io.ObjectStreamException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; @@ -34,6 +33,8 @@ import java.util.Map; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -63,44 +64,7 @@ public UserInjector(Settings settings, ThreadPool threadPool, AuditLog auditLog, } - public static class InjectedUser extends User { - private transient TransportAddress transportAddress; - - public InjectedUser(String name) { - super(name); - } - - private Object writeReplace() throws ObjectStreamException { - User user = new User(getName()); - user.addRoles(getRoles()); - user.addSecurityRoles(getSecurityRoles()); - user.setRequestedTenant(getRequestedTenant()); - user.addAttributes(getCustomAttributesMap()); - user.setInjected(true); - return user; - } - - public TransportAddress getTransportAddress() { - return transportAddress; - } - - public void setTransportAddress(String addr) throws UnknownHostException, IllegalArgumentException { - int lastColonIndex = addr.lastIndexOf(':'); - if (lastColonIndex == -1) { - throw new IllegalArgumentException("Remote address must have format ip:port"); - } - - String ip = addr.substring(0, lastColonIndex); - String portString = addr.substring(lastColonIndex + 1); - - InetAddress iAdress = InetAddress.getByName(ip); - int port = Integer.parseInt(portString); - - this.transportAddress = new TransportAddress(iAdress, port); - } - } - - public InjectedUser getInjectedUser() { + public Result getInjectedUser() { if (!injectUserEnabled) { return null; } @@ -123,59 +87,74 @@ public InjectedUser getInjectedUser() { } // username - if (Strings.isNullOrEmpty(parts[0])) { + String userName = parts[0]; + if (Strings.isNullOrEmpty(userName)) { log.error("Username must not be null, user string was '{}.' User injection failed.", injectedUserString); return null; } - final InjectedUser injectedUser = new InjectedUser(parts[0]); - // backend roles + ImmutableSet backendRoles = ImmutableSet.of(); if (parts.length > 1 && !Strings.isNullOrEmpty(parts[1])) { if (parts[1].length() > 0) { - injectedUser.addRoles(Arrays.asList(parts[1].split(","))); + backendRoles = ImmutableSet.copyOf(Arrays.asList(parts[1].split(","))); } } // custom attributes + ImmutableMap customAttributes = ImmutableMap.of(); if (parts.length > 3 && !Strings.isNullOrEmpty(parts[3])) { - Map attributes = mapFromArray((parts[3].split(","))); - if (attributes == null) { + customAttributes = mapFromArray((parts[3].split(","))); + if (customAttributes == null) { log.error("Could not parse custom attributes {}, user injection failed.", parts[3]); return null; - } else { - injectedUser.addAttributes(attributes); } } // requested tenant + String requestedTenant = null; if (parts.length > 4 && !Strings.isNullOrEmpty(parts[4])) { - injectedUser.setRequestedTenant(parts[4]); + requestedTenant = parts[4]; } // remote IP - we can set it only once, so we do it last. If non is given, // BackendRegistry/XFFResolver will do the job + TransportAddress transportAddress = null; if (parts.length > 2 && !Strings.isNullOrEmpty(parts[2])) { try { - injectedUser.setTransportAddress(parts[2]); + transportAddress = parseTransportAddress(parts[2]); } catch (UnknownHostException | IllegalArgumentException e) { log.error("Cannot parse remote IP or port: {}, user injection failed.", parts[2], e); return null; } } - // mark user injected for proper admin handling - injectedUser.setInjected(true); + User injectedUser = new User(userName, backendRoles, ImmutableSet.of(), requestedTenant, customAttributes, true); if (log.isTraceEnabled()) { log.trace("Injected user object:{} ", injectedUser.toString()); } - return injectedUser; + return new Result(injectedUser, transportAddress); + } + + public TransportAddress parseTransportAddress(String addr) throws UnknownHostException, IllegalArgumentException { + int lastColonIndex = addr.lastIndexOf(':'); + if (lastColonIndex == -1) { + throw new IllegalArgumentException("Remote address must have format ip:port"); + } + + String ip = addr.substring(0, lastColonIndex); + String portString = addr.substring(lastColonIndex + 1); + + InetAddress iAdress = InetAddress.getByName(ip); + int port = Integer.parseInt(portString); + + return new TransportAddress(iAdress, port); } boolean injectUser(SecurityRequestChannel request) { - InjectedUser injectedUser = getInjectedUser(); + Result injectedUser = getInjectedUser(); if (injectedUser == null) { return false; } @@ -188,15 +167,15 @@ boolean injectUser(SecurityRequestChannel request) { threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, xffResolver.resolve(request)); } - threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, injectedUser); - auditLog.logSucceededLogin(injectedUser.getName(), true, null, request); + threadPool.getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, injectedUser.getUser()); + auditLog.logSucceededLogin(injectedUser.getUser().getName(), true, null, request); return true; } - protected Map mapFromArray(String... keyValues) { + protected ImmutableMap mapFromArray(String... keyValues) { if (keyValues == null) { - return Map.of(); + return ImmutableMap.of(); } if (keyValues.length % 2 != 0) { log.error("Expected even number of key/value pairs, got {}.", Arrays.toString(keyValues)); @@ -207,7 +186,25 @@ protected Map mapFromArray(String... keyValues) { for (int i = 0; i < keyValues.length; i += 2) { map.put(keyValues[i], keyValues[i + 1]); } - return map; + return ImmutableMap.copyOf(map); + } + + public static class Result { + private final User user; + private final TransportAddress transportAddress; + + public Result(User user, TransportAddress transportAddress) { + this.user = user; + this.transportAddress = transportAddress; + } + + public User getUser() { + return user; + } + + public TransportAddress getTransportAddress() { + return transportAddress; + } } } diff --git a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java index be09638d9d..4536c92bb0 100644 --- a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java @@ -30,14 +30,17 @@ import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.opensearch.OpenSearchSecurityException; import org.opensearch.security.auth.AuthenticationBackend; import org.opensearch.security.auth.AuthorizationBackend; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.hasher.PasswordHasher; import org.opensearch.security.securityconf.InternalUsersModel; import org.opensearch.security.user.AuthCredentials; @@ -45,7 +48,7 @@ import org.greenrobot.eventbus.Subscribe; -public class InternalAuthenticationBackend implements AuthenticationBackend, AuthorizationBackend { +public class InternalAuthenticationBackend implements AuthenticationBackend, ImpersonationBackend, AuthorizationBackend { private final PasswordHasher passwordHasher; private InternalUsersModel internalUsersModel; @@ -55,20 +58,18 @@ public InternalAuthenticationBackend(PasswordHasher passwordHasher) { } @Override - public boolean exists(User user) { - + public Optional impersonate(User user) { if (user == null || internalUsersModel == null) { - return false; + return Optional.empty(); } final boolean exists = internalUsersModel.exists(user.getName()); if (exists) { - user.addRoles(internalUsersModel.getBackenRoles(user.getName())); // FIX https://github.com/opendistro-for-elasticsearch/security/pull/23 // Credits to @turettn final Map customAttributes = internalUsersModel.getAttributes(user.getName()); - Map attributeMap = new HashMap<>(); + ImmutableMap.Builder attributeMap = ImmutableMap.builder(); if (customAttributes != null) { for (Entry attributeEntry : customAttributes.entrySet()) { @@ -76,16 +77,14 @@ public boolean exists(User user) { } } - final List securityRoles = internalUsersModel.getSecurityRoles(user.getName()); - if (securityRoles != null) { - user.addSecurityRoles(securityRoles); - } - - user.addAttributes(attributeMap); - return true; + return Optional.of( + user.withRoles(internalUsersModel.getBackendRoles(user.getName())) + .withSecurityRoles(internalUsersModel.getSecurityRoles(user.getName())) + .withAttributes(attributeMap.build()) + ); + } else { + return Optional.empty(); } - - return false; } /** @@ -133,21 +132,14 @@ public User authenticate(final AuthCredentials credentials) { try { if (passwordMatchesHash(hash, array) && userExists) { - final List roles = internalUsersModel.getBackenRoles(credentials.getUsername()); - final Map customAttributes = internalUsersModel.getAttributes(credentials.getUsername()); - if (customAttributes != null) { - for (Entry attributeName : customAttributes.entrySet()) { - credentials.addAttribute("attr.internal." + attributeName.getKey(), attributeName.getValue()); - } - } - - final User user = new User(credentials.getUsername(), roles, credentials); - - final List securityRoles = internalUsersModel.getSecurityRoles(credentials.getUsername()); - if (securityRoles != null) { - user.addSecurityRoles(securityRoles); - } - return user; + ImmutableSet backendRoles = internalUsersModel.getBackendRoles(credentials.getUsername()); + ImmutableSet securityRoles = internalUsersModel.getSecurityRoles(credentials.getUsername()); + ImmutableMap attributeMap = ImmutableMap.builder() + .putAll(credentials.getAttributes()) + .putAll(prefixedAttributeMap(internalUsersModel.getAttributes(credentials.getUsername()))) + .build(); + + return new User(credentials.getUsername(), backendRoles, securityRoles, null, attributeMap, false); } else { if (!userExists) { throw new OpenSearchSecurityException(credentials.getUsername() + " not found"); @@ -167,22 +159,20 @@ public String getType() { } @Override - public void fillRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { - + public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { if (internalUsersModel == null) { throw new OpenSearchSecurityException( "Internal authentication backend not configured. May be OpenSearch Security is not initialized." ); - } - if (exists(user)) { - final List roles = internalUsersModel.getBackenRoles(user.getName()); - if (roles != null && !roles.isEmpty() && user != null) { - user.addRoles(roles); - } + if (internalUsersModel.exists(user.getName())) { + return user.withRoles(internalUsersModel.getBackendRoles(user.getName())) + .withSecurityRoles(internalUsersModel.getSecurityRoles(user.getName())) + .withAttributes(prefixedAttributeMap(internalUsersModel.getAttributes(user.getName()))); + } else { + return user; } - } @Subscribe @@ -190,4 +180,14 @@ public void onInternalUsersModelChanged(InternalUsersModel ium) { this.internalUsersModel = ium; } + ImmutableMap prefixedAttributeMap(ImmutableMap attributeMap) { + ImmutableMap.Builder result = ImmutableMap.builder(); + + for (Entry attributeEntry : attributeMap.entrySet()) { + result.put("attr.internal." + attributeEntry.getKey(), attributeEntry.getValue()); + } + + return result.build(); + } + } diff --git a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java index 299a1a4577..de2a41f6b9 100644 --- a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java @@ -27,13 +27,16 @@ package org.opensearch.security.auth.internal; import java.nio.file.Path; +import java.util.Optional; import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.AuthenticationContext; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -public class NoOpAuthenticationBackend implements AuthenticationBackend { +public class NoOpAuthenticationBackend implements AuthenticationBackend, ImpersonationBackend { public NoOpAuthenticationBackend(final Settings settings, final Path configPath) { super(); @@ -46,14 +49,18 @@ public String getType() { @Override public User authenticate(final AuthCredentials credentials) { - User user = new User(credentials.getUsername(), credentials.getBackendRoles(), credentials); - user.addSecurityRoles(credentials.getSecurityRoles()); - return user; + return new User( + credentials.getUsername(), + credentials.getBackendRoles(), + credentials.getSecurityRoles(), + null, + credentials.getAttributes(), + false + ); } @Override - public boolean exists(User user) { - return true; + public Optional impersonate(User user) { + return Optional.of(user); } - } diff --git a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java index 581cfc8da6..2cf128fd9a 100644 --- a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java @@ -45,8 +45,7 @@ public String getType() { } @Override - public void fillRoles(final User user, final AuthCredentials authCreds) { - // no-op + public User addRoles(User user, AuthCredentials credentials) { + return user; } - } diff --git a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java index cedcb837ec..caaf2df72e 100755 --- a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java @@ -19,6 +19,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -32,6 +33,7 @@ import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.LdapHelper; import org.opensearch.security.auth.ldap.util.Utils; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; @@ -46,7 +48,7 @@ import static org.opensearch.security.setting.DeprecatedSettings.checkForDeprecatedSetting; -public class LDAPAuthenticationBackend implements AuthenticationBackend { +public class LDAPAuthenticationBackend implements AuthenticationBackend, ImpersonationBackend { static final int ZERO_PLACEHOLDER = 0; static final String DEFAULT_USERBASE = ""; @@ -160,7 +162,7 @@ public String getType() { } @Override - public boolean exists(final User user) { + public Optional impersonate(User user) { Connection ldapConnection = null; String userName = user.getName(); @@ -178,19 +180,19 @@ public boolean exists(final User user) { this.returnAttributes, this.shouldFollowReferrals ); - boolean exists = userEntry != null; - if (exists) { - user.addAttributes( - LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher) + if (userEntry != null) { + return Optional.of( + user.withAttributes( + LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher) + ) ); + } else { + return Optional.empty(); } - - return exists; - } catch (final Exception e) { - log.warn("User {} does not exist due to ", userName, e); - return false; + log.warn("User {} does not exist due to exception", userName, e); + return Optional.empty(); } finally { Utils.unbindAndCloseSilently(ldapConnection); } diff --git a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java index 8da9986c13..58194d04f8 100755 --- a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java @@ -686,10 +686,10 @@ private static void configureSSL(final ConnectionConfig config, final Settings s } @Override - public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { + public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { if (user == null) { - return; + return user; } String authenticatedUser; @@ -738,12 +738,13 @@ public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) if (isDebugEnabled) { log.debug("Skipped search roles of user {}/{}", authenticatedUser, originalUserName); } - return; + return user; } Connection connection = null; try { + Set additionalRoles = new HashSet<>(); if (entry == null || dn == null) { @@ -969,7 +970,7 @@ public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) log.debug("Role was excluded or empty, attribute: '{}' for entry: {}", roleName, roleLdapName); } } else { - user.addRole(role); + additionalRoles.add(role); } } @@ -983,16 +984,14 @@ public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) log.debug("Role was excluded or empty, attribute: '{}' for entry: {}", roleName, roleLdapName); } } else { - user.addRole(role); + additionalRoles.add(role); } } } // add all non-LDAP roles from user attributes to the final set of backend roles - for (String nonLdapRoleName : nonLdapRoles) { - user.addRole(nonLdapRoleName); - } + additionalRoles.addAll(nonLdapRoles); if (isDebugEnabled) { log.debug("Roles for {} -> {}", user.getName(), user.getRoles()); @@ -1002,6 +1001,8 @@ public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) log.trace("returned user: {}", user); } + return user.withRoles(additionalRoles); + } catch (final Exception e) { if (isDebugEnabled) { log.debug("Unable to fill user roles due to ", e); diff --git a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java index 98f424e486..2b438cc83b 100755 --- a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java +++ b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java @@ -19,6 +19,7 @@ import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Collections; +import java.util.Optional; import java.util.UUID; import org.apache.logging.log4j.LogManager; @@ -29,6 +30,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; import org.opensearch.security.auth.Destroyable; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.Utils; import org.opensearch.security.support.WildcardMatcher; @@ -47,7 +49,7 @@ import org.ldaptive.ReturnAttributes; import org.ldaptive.pool.ConnectionPool; -public class LDAPAuthenticationBackend2 implements AuthenticationBackend, Destroyable { +public class LDAPAuthenticationBackend2 implements AuthenticationBackend, ImpersonationBackend, Destroyable { protected static final Logger log = LogManager.getLogger(LDAPAuthenticationBackend2.class); @@ -189,50 +191,42 @@ public String getType() { @SuppressWarnings("removal") @Override - public boolean exists(final User user) { + public Optional impersonate(User user) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new SpecialPermission()); } - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Boolean run() { - return exists0(user); - } - }); - - } - - private boolean exists0(final User user) { - Connection ldapConnection = null; - String userName = user.getName(); - - if (user instanceof LdapUser) { - userName = ((LdapUser) user).getUserEntry().getDn(); - } - - try { - ldapConnection = this.connectionFactory.getConnection(); - ldapConnection.open(); - LdapEntry userEntry = this.userSearcher.exists(ldapConnection, userName, this.returnAttributes, this.shouldFollowReferrals); - - boolean exists = userEntry != null; + return AccessController.doPrivileged((PrivilegedAction>) () -> { + Connection ldapConnection = null; + String userName = user.getName(); - if (exists) { - user.addAttributes( - LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, whitelistedCustomLdapAttrMatcher) - ); + if (user instanceof LdapUser) { + userName = ((LdapUser) user).getUserEntry().getDn(); } - return exists; - } catch (final Exception e) { - log.warn("User {} does not exist due to exception", userName, e); - return false; - } finally { - Utils.unbindAndCloseSilently(ldapConnection); - } + try { + ldapConnection = this.connectionFactory.getConnection(); + ldapConnection.open(); + LdapEntry userEntry = this.userSearcher.exists(ldapConnection, userName, this.returnAttributes, this.shouldFollowReferrals); + + if (userEntry != null) { + return Optional.of( + user.withAttributes( + LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, whitelistedCustomLdapAttrMatcher) + ) + ); + } else { + return Optional.empty(); + } + } catch (final Exception e) { + log.warn("User {} does not exist due to exception", userName, e); + return Optional.empty(); + } finally { + Utils.unbindAndCloseSilently(ldapConnection); + } + }); } @SuppressWarnings("removal") diff --git a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java index f7676adbfb..3526e71e6c 100755 --- a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java +++ b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java @@ -124,7 +124,7 @@ private static List> convertOldStyleSettingsToNewSty @SuppressWarnings("removal") @Override - public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { + public User addRoles(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -133,11 +133,10 @@ public void fillRoles(final User user, final AuthCredentials optionalAuthCreds) } try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override - public Void run() throws Exception { - fillRoles0(user, optionalAuthCreds); - return null; + public User run() throws Exception { + return addRoles0(user, optionalAuthCreds); } }); } catch (PrivilegedActionException e) { @@ -151,10 +150,10 @@ public Void run() throws Exception { } } - private void fillRoles0(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { + private User addRoles0(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { if (user == null) { - return; + return user; } String authenticatedUser; @@ -192,9 +191,11 @@ private void fillRoles0(final User user, final AuthCredentials optionalAuthCreds if (isDebugEnabled) { log.debug("Skipped search roles of user {}/{}", authenticatedUser, originalUserName); } - return; + return user; } + Set additionalRoles = new HashSet<>(); + try (Connection connection = this.connectionFactory.getConnection()) { connection.open(); @@ -385,7 +386,7 @@ private void fillRoles0(final User user, final AuthCredentials optionalAuthCreds log.debug("Role was excluded or empty attribute '{}' for entry {}", roleName, roleLdapName); } } else { - user.addRole(role); + additionalRoles.add(role); } } @@ -399,16 +400,14 @@ private void fillRoles0(final User user, final AuthCredentials optionalAuthCreds log.debug("Role was excluded or empty attribute '{}' for entry {}", roleName, roleLdapName); } } else { - user.addRole(role); + additionalRoles.add(role); } } } // add all non-LDAP roles from user attributes to the final set of backend roles - for (String nonLdapRoleName : nonLdapRoles) { - user.addRole(nonLdapRoleName); - } + additionalRoles.addAll(nonLdapRoles); if (isDebugEnabled) { log.debug("Roles for {} -> {}", user.getName(), user.getRoles()); @@ -418,6 +417,7 @@ private void fillRoles0(final User user, final AuthCredentials optionalAuthCreds log.trace("returned user: {}", user); } + return user.withRoles(additionalRoles); } catch (final Exception e) { if (isDebugEnabled) { log.debug("Unable to fill user roles due to ", e); diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 2e0b61289f..642679a8fd 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -190,8 +190,12 @@ private void ap } final Set injectedRoles = rolesInjector.injectUserAndRoles(request, action, task, threadContext); User user = threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); - if (user == null && (user = userInjector.getInjectedUser()) != null) { - threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, user); + if (user == null) { + UserInjector.Result injectedUser = userInjector.getInjectedUser(); + if (injectedUser != null) { + user = injectedUser.getUser(); + threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, user); + } } final boolean userIsAdmin = isUserAdmin(user, adminDns); final boolean interClusterRequest = HeaderHelper.isInterClusterRequest(threadContext); diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index 76e0d83434..c29cc7ab84 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -351,8 +351,6 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) context.setMappedRoles(mappedRoles); } - // Add the security roles for this user so that they can be used for DLS parameter substitution. - user.addSecurityRoles(mappedRoles); setUserInfoInThreadContext(user); final boolean isDebugEnabled = log.isDebugEnabled(); diff --git a/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java b/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java index 1080a8e60c..392e4a38ed 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java @@ -27,9 +27,10 @@ package org.opensearch.security.rest; import java.io.IOException; -import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -145,14 +146,14 @@ public void accept(RestChannel channel) throws Exception { builder.field( "size_of_custom_attributes", RamUsageEstimator.humanReadableUnits( - Base64Helper.serializeObject((Serializable) user.getCustomAttributesMap()) + Base64Helper.serializeObject(new HashMap<>(user.getCustomAttributesMap())) .getBytes(StandardCharsets.UTF_8).length ) ); builder.field( "size_of_backendroles", RamUsageEstimator.humanReadableUnits( - Base64Helper.serializeObject((Serializable) user.getRoles()).getBytes(StandardCharsets.UTF_8).length + Base64Helper.serializeObject(new HashSet<>(user.getRoles())).getBytes(StandardCharsets.UTF_8).length ) ); } catch (Throwable e) { diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java index 9d6dafc857..be242e38d8 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java @@ -293,10 +293,7 @@ private Set map(final User user, final TransportAddress caller) { return Collections.emptySet(); } - final Set securityRoles = new HashSet<>(); - synchronized (user.getSecurityRoles()) { - securityRoles.addAll(user.getSecurityRoles()); - } + final Set securityRoles = new HashSet<>(user.getSecurityRoles()); if (rolesMappingResolution == ConfigConstants.RolesMappingResolution.BOTH || rolesMappingResolution == ConfigConstants.RolesMappingResolution.BACKENDROLES_ONLY) { diff --git a/src/main/java/org/opensearch/security/securityconf/DynamicConfigFactory.java b/src/main/java/org/opensearch/security/securityconf/DynamicConfigFactory.java index 365a6e0e66..0f5b5dea65 100644 --- a/src/main/java/org/opensearch/security/securityconf/DynamicConfigFactory.java +++ b/src/main/java/org/opensearch/security/securityconf/DynamicConfigFactory.java @@ -29,13 +29,12 @@ import java.io.IOException; import java.nio.file.Path; -import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; -import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.fasterxml.jackson.databind.JsonNode; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -321,15 +320,15 @@ public boolean exists(String user) { } @Override - public List getBackenRoles(String user) { + public ImmutableSet getBackendRoles(String user) { InternalUserV7 tmp = internalUserV7SecurityDynamicConfiguration.getCEntry(user); - return tmp == null ? null : tmp.getBackend_roles(); + return tmp == null ? ImmutableSet.of() : ImmutableSet.copyOf(tmp.getBackend_roles()); } @Override - public Map getAttributes(String user) { + public ImmutableMap getAttributes(String user) { InternalUserV7 tmp = internalUserV7SecurityDynamicConfiguration.getCEntry(user); - return tmp == null ? null : tmp.getAttributes(); + return tmp == null ? ImmutableMap.of() : ImmutableMap.copyOf(tmp.getAttributes()); } @Override @@ -344,17 +343,17 @@ public String getHash(String user) { return tmp == null ? null : tmp.getHash(); } - public List getSecurityRoles(String user) { + public ImmutableSet getSecurityRoles(String user) { InternalUserV7 tmp = internalUserV7SecurityDynamicConfiguration.getCEntry(user); // Security roles should only contain roles that exist in the roles dynamic config. // We should filter out any roles that have hidden rolesmapping. return tmp == null - ? ImmutableList.of() + ? ImmutableSet.of() : tmp.getOpendistro_security_roles() .stream() .filter(role -> !isRolesMappingHidden(role) && rolesV7SecurityDynamicConfiguration.exists(role)) - .collect(ImmutableList.toImmutableList()); + .collect(ImmutableSet.toImmutableSet()); } // Remove any hidden rolesmapping from the security roles diff --git a/src/main/java/org/opensearch/security/securityconf/InternalUsersModel.java b/src/main/java/org/opensearch/security/securityconf/InternalUsersModel.java index 8ce40266cf..ff232e94a5 100644 --- a/src/main/java/org/opensearch/security/securityconf/InternalUsersModel.java +++ b/src/main/java/org/opensearch/security/securityconf/InternalUsersModel.java @@ -27,21 +27,21 @@ package org.opensearch.security.securityconf; -import java.util.List; -import java.util.Map; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; public abstract class InternalUsersModel { public abstract boolean exists(String user); - public abstract List getBackenRoles(String user); + public abstract ImmutableSet getBackendRoles(String user); - public abstract Map getAttributes(String user); + public abstract ImmutableMap getAttributes(String user); public abstract String getDescription(String user); public abstract String getHash(String user); - public abstract List getSecurityRoles(String user); + public abstract ImmutableSet getSecurityRoles(String user); } diff --git a/src/main/java/org/opensearch/security/support/Base64Helper.java b/src/main/java/org/opensearch/security/support/Base64Helper.java index 6c28e0a6ea..6b1b79be9b 100644 --- a/src/main/java/org/opensearch/security/support/Base64Helper.java +++ b/src/main/java/org/opensearch/security/support/Base64Helper.java @@ -42,6 +42,7 @@ import org.opensearch.OpenSearchException; import org.opensearch.core.common.Strings; +import org.opensearch.security.user.User; import static org.opensearch.security.support.SafeSerializationUtils.isSafeClass; @@ -106,8 +107,12 @@ public SafeObjectInputStream(InputStream in) throws IOException { @Override protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - Class clazz = super.resolveClass(desc); + + if (clazz.equals(User.class)) { + return org.opensearch.security.user.serialized.User.class; + } + if (isSafeClass(clazz)) { return clazz; } diff --git a/src/main/java/org/opensearch/security/support/SafeSerializationUtils.java b/src/main/java/org/opensearch/security/support/SafeSerializationUtils.java index de55334a99..e3ac97ddb7 100644 --- a/src/main/java/org/opensearch/security/support/SafeSerializationUtils.java +++ b/src/main/java/org/opensearch/security/support/SafeSerializationUtils.java @@ -24,9 +24,6 @@ import com.google.common.collect.ImmutableSet; -import org.opensearch.security.auth.UserInjector; -import org.opensearch.security.user.User; - import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.AbstractLdapBean; import org.ldaptive.LdapAttribute; @@ -46,8 +43,8 @@ public final class SafeSerializationUtils { SocketAddress.class, InetSocketAddress.class, Pattern.class, - User.class, - UserInjector.InjectedUser.class, + org.opensearch.security.user.User.class, + org.opensearch.security.user.serialized.User.class, SourceFieldsContext.class, LdapUser.class, SearchEntry.class, diff --git a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java index 72d55de00f..5ae9cbb591 100644 --- a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java +++ b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java @@ -63,6 +63,7 @@ import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; +import org.opensearch.security.user.UserFactory; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.Transport.Connection; import org.opensearch.transport.TransportException; @@ -86,6 +87,7 @@ public class SecurityInterceptor { private final ClusterInfoHolder clusterInfoHolder; private final SSLConfig SSLConfig; private final Supplier actionTraceEnabled; + private final UserFactory userFactory; public SecurityInterceptor( final Settings settings, @@ -98,7 +100,8 @@ public SecurityInterceptor( final SslExceptionHandler sslExceptionHandler, final ClusterInfoHolder clusterInfoHolder, final SSLConfig SSLConfig, - final Supplier actionTraceSupplier + final Supplier actionTraceSupplier, + final UserFactory userFactory ) { this.backendRegistry = backendRegistry; this.auditLog = auditLog; @@ -111,6 +114,7 @@ public SecurityInterceptor( this.clusterInfoHolder = clusterInfoHolder; this.SSLConfig = SSLConfig; this.actionTraceEnabled = actionTraceSupplier; + this.userFactory = userFactory; } public SecurityRequestHandler getHandler(String action, TransportRequestHandler actualHandler) { @@ -123,7 +127,8 @@ public SecurityRequestHandler getHandler(String requestEvalProvider, cs, SSLConfig, - sslExceptionHandler + sslExceptionHandler, + userFactory ); } @@ -311,7 +316,7 @@ && getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN_HEADE if (userHeader == null) { // put as headers for other requests if (origUser != null) { - getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(origUser)); + getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, origUser.toSerializedBase64()); } else if (StringUtils.isNotEmpty(injectedRolesString)) { getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_ROLES_HEADER, injectedRolesString); } else if (StringUtils.isNotEmpty(injectedUserString)) { diff --git a/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java b/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java index 45aa399a84..4198969fde 100644 --- a/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java +++ b/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java @@ -29,7 +29,6 @@ // CS-SUPPRESS-SINGLE: RegexpSingleline Extensions manager used to allow/disallow TLS connections to extensions import java.net.InetSocketAddress; import java.security.cert.X509Certificate; -import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; @@ -55,7 +54,7 @@ import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.HeaderHelper; -import org.opensearch.security.user.User; +import org.opensearch.security.user.UserFactory; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportChannel; @@ -70,6 +69,7 @@ public class SecurityRequestHandler extends Security private final AuditLog auditLog; private final InterClusterRequestEvaluator requestEvalProvider; private final ClusterService cs; + private final UserFactory userFactory; SecurityRequestHandler( String action, @@ -80,12 +80,14 @@ public class SecurityRequestHandler extends Security final InterClusterRequestEvaluator requestEvalProvider, final ClusterService cs, final SSLConfig SSLConfig, - final SslExceptionHandler sslExceptionHandler + final SslExceptionHandler sslExceptionHandler, + final UserFactory userFactory ) { super(action, actualHandler, threadPool, principalExtractor, SSLConfig, sslExceptionHandler); this.auditLog = auditLog; this.requestEvalProvider = requestEvalProvider; this.cs = cs; + this.userFactory = userFactory; } @Override @@ -181,7 +183,7 @@ protected void messageReceivedDecorate( } else { getThreadContext().putTransient( ConfigConstants.OPENDISTRO_SECURITY_USER, - Objects.requireNonNull((User) Base64Helper.deserializeObject(userHeader)) + this.userFactory.fromSerializedBase64(userHeader) ); } diff --git a/src/main/java/org/opensearch/security/user/AuthCredentials.java b/src/main/java/org/opensearch/security/user/AuthCredentials.java index beb3ae1733..da43db2b38 100644 --- a/src/main/java/org/opensearch/security/user/AuthCredentials.java +++ b/src/main/java/org/opensearch/security/user/AuthCredentials.java @@ -29,13 +29,15 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + import org.opensearch.OpenSearchSecurityException; /** @@ -213,16 +215,16 @@ public String toString() { * * @return Defensive copy of the roles this user is member of. */ - public Set getBackendRoles() { - return new HashSet(backendRoles); + public ImmutableSet getBackendRoles() { + return ImmutableSet.copyOf(backendRoles); } /** * * @return Defensive copy of the security roles this user is member of. */ - public Set getSecurityRoles() { - return Set.copyOf(securityRoles); + public ImmutableSet getSecurityRoles() { + return ImmutableSet.copyOf(securityRoles); } public boolean isComplete() { @@ -248,7 +250,7 @@ public void addAttribute(String name, String value) { } } - public Map getAttributes() { - return Collections.unmodifiableMap(this.attributes); + public ImmutableMap getAttributes() { + return ImmutableMap.copyOf(this.attributes); } } diff --git a/src/main/java/org/opensearch/security/user/User.java b/src/main/java/org/opensearch/security/user/User.java index 40923293f4..230f78224e 100644 --- a/src/main/java/org/opensearch/security/user/User.java +++ b/src/main/java/org/opensearch/security/user/User.java @@ -26,15 +26,24 @@ package org.opensearch.security.user; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.io.Serial; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Set; +import java.util.Objects; -import com.google.common.collect.Lists; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +import org.opensearch.security.support.Base64Helper; /** * A authenticated user and attributes associated to them (like roles, tenant, custom attributes) @@ -44,33 +53,40 @@ */ public class User implements Serializable, CustomAttributesAware { - public static final User ANONYMOUS = new User( - "opendistro_security_anonymous", - Lists.newArrayList("opendistro_security_anonymous_backendrole"), - null - ); + public static final User ANONYMOUS = new User("opendistro_security_anonymous").withRole("opendistro_security_anonymous_backendrole"); // This is a default user that is injected into a transport request when a user info is not present and passive_intertransport_auth is // enabled. // This is to be used in scenarios where some of the nodes do not have security enabled, and therefore do not pass any user information // in threadcontext, yet we need the communication to not break between the nodes. // Attach the required permissions to either the user or the backend role. - public static final User DEFAULT_TRANSPORT_USER = new User( - "opendistro_security_default_transport_user", - Lists.newArrayList("opendistro_security_default_transport_backendrole"), - null + public static final User DEFAULT_TRANSPORT_USER = new User("opendistro_security_default_transport_user").withRole( + "opendistro_security_default_transport_backendrole" ); + /** + * Deserializes the given serialized from of a user object and returns the actual user object. + * + * Note: Instead of using this method, prefer to use UserFactory.Caching to benefit from already parsed user objects. + */ + public static User fromSerializedBase64(String serializedBase64) { + User user = (User) Base64Helper.deserializeObject(serializedBase64); + user.serializedBase64 = serializedBase64; + return user; + } + private static final long serialVersionUID = -5500938501822658596L; private final String name; + /** * roles == backend_roles */ - private final Set roles = Collections.synchronizedSet(new HashSet()); - private final Set securityRoles = Collections.synchronizedSet(new HashSet()); - private String requestedTenant; - private Map attributes = Collections.synchronizedMap(new HashMap<>()); - private boolean isInjected = false; + private final ImmutableSet roles; + private final ImmutableSet securityRoles; + private final String requestedTenant; + private final ImmutableMap attributes; + private final boolean isInjected; + private volatile transient String serializedBase64; /** * Create a new authenticated user @@ -81,22 +97,14 @@ public class User implements Serializable, CustomAttributesAware { * @throws IllegalArgumentException if name is null or empty */ public User(final String name, final Collection roles, final AuthCredentials customAttributes) { - super(); - - if (name == null || name.isEmpty()) { - throw new IllegalArgumentException("name must not be null or empty"); - } - - this.name = name; - - if (roles != null) { - this.addRoles(roles); - } - - if (customAttributes != null) { - this.attributes.putAll(customAttributes.getAttributes()); - } - + this( + name, + ImmutableSet.copyOf(roles), + ImmutableSet.of(), + null, + customAttributes != null ? ImmutableMap.copyOf(customAttributes.getAttributes()) : ImmutableMap.of(), + false + ); } /** @@ -106,7 +114,27 @@ public User(final String name, final Collection roles, final AuthCredent * @throws IllegalArgumentException if name is null or empty */ public User(final String name) { - this(name, null, null); + this(name, ImmutableSet.of(), null); + } + + public User( + String name, + ImmutableSet roles, + ImmutableSet securityRoles, + String requestedTenant, + ImmutableMap attributes, + boolean isInjected + ) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("name must not be null or empty"); + } + + this.name = name; + this.roles = Objects.requireNonNull(roles); + this.securityRoles = Objects.requireNonNull(securityRoles); + this.requestedTenant = requestedTenant; + this.attributes = Objects.requireNonNull(attributes); + this.isInjected = isInjected; } public final String getName() { @@ -117,8 +145,8 @@ public final String getName() { * * @return A unmodifiable set of the backend roles this user is a member of */ - public final Set getRoles() { - return Collections.unmodifiableSet(roles); + public ImmutableSet getRoles() { + return this.roles; } /** @@ -126,8 +154,15 @@ public final Set getRoles() { * * @param role The backend role */ - public final void addRole(final String role) { - this.roles.add(role); + public User withRole(String role) { + return new User( + this.name, + new ImmutableSet.Builder().addAll(this.roles).add(role).build(), + this.securityRoles, + this.requestedTenant, + this.attributes, + this.isInjected + ); } /** @@ -135,30 +170,38 @@ public final void addRole(final String role) { * * @param roles The backend roles */ - public final void addRoles(final Collection roles) { - if (roles != null) { - this.roles.addAll(roles); + public User withRoles(Collection roles) { + if (roles == null || roles.isEmpty()) { + return this; + } else { + return new User( + this.name, + new ImmutableSet.Builder().addAll(this.roles).addAll(roles).build(), + this.securityRoles, + this.requestedTenant, + this.attributes, + this.isInjected + ); } } - /** - * Check if this user is a member of a backend role - * - * @param role The backend role - * @return true if this user is a member of the backend role, false otherwise - */ - public final boolean isUserInRole(final String role) { - return this.roles.contains(role); - } - /** * Associate this user with a set of custom attributes * * @param attributes custom attributes */ - public final void addAttributes(final Map attributes) { - if (attributes != null) { - this.attributes.putAll(attributes); + public User withAttributes(Map attributes) { + if (attributes == null || attributes.isEmpty()) { + return this; + } else { + return new User( + this.name, + this.roles, + this.securityRoles, + this.requestedTenant, + new ImmutableMap.Builder().putAll(this.attributes).putAll(attributes).build(), + this.isInjected + ); } } @@ -166,18 +209,18 @@ public final String getRequestedTenant() { return requestedTenant; } - public final void setRequestedTenant(String requestedTenant) { - this.requestedTenant = requestedTenant; + public User withRequestedTenant(String requestedTenant) { + if (Objects.equals(requestedTenant, this.requestedTenant)) { + return this; + } else { + return new User(this.name, this.roles, this.securityRoles, requestedTenant, this.attributes, this.isInjected); + } } public boolean isInjected() { return isInjected; } - public void setInjected(boolean isInjected) { - this.isInjected = isInjected; - } - public final String toStringWithAttributes() { return "User [name=" + name @@ -225,39 +268,32 @@ public final boolean equals(final Object obj) { return true; } - /** - * Copy all backend roles from another user - * - * @param user The user from which the backend roles should be copied over - */ - public final void copyRolesFrom(final User user) { - if (user != null) { - this.addRoles(user.getRoles()); - } - } - /** * Get the custom attributes associated with this user * - * @return A modifiable map with all the current custom attributes associated with this user + * @return An immutable map with all the current custom attributes associated with this user */ - public synchronized final Map getCustomAttributesMap() { - if (attributes == null) { - attributes = Collections.synchronizedMap(new HashMap<>()); - } - return attributes; + public ImmutableMap getCustomAttributesMap() { + return this.attributes; } - public final void addSecurityRoles(final Collection securityRoles) { - if (securityRoles != null && this.securityRoles != null) { - this.securityRoles.addAll(securityRoles); + public User withSecurityRoles(Collection securityRoles) { + if (securityRoles == null || securityRoles.isEmpty()) { + return this; + } else { + return new User( + this.name, + this.roles, + new ImmutableSet.Builder().addAll(this.securityRoles).addAll(securityRoles).build(), + this.requestedTenant, + this.attributes, + this.isInjected + ); } } - public final Set getSecurityRoles() { - return this.securityRoles == null - ? Collections.synchronizedSet(Collections.emptySet()) - : Collections.unmodifiableSet(this.securityRoles); + public ImmutableSet getSecurityRoles() { + return this.securityRoles; } /** @@ -278,4 +314,47 @@ public boolean isServiceAccount() { public boolean isPluginUser() { return name != null && name.startsWith("plugin:"); } + + public String toSerializedBase64() { + String result = this.serializedBase64; + + if (result == null) { + this.serializedBase64 = result = Base64Helper.serializeObject(this); + } + + return result; + } + + + void readObject(ObjectInputStream stream) throws InvalidObjectException { + // This object is not supposed to directly read in order to keep compatibility with older OpenSearch versions + throw new InvalidObjectException("Use org.opensearch.security.user.serialized.User"); + } + + @Serial + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("name", String.class), + new ObjectStreamField("roles", Collections.synchronizedSet(Collections.emptySet()).getClass()), + new ObjectStreamField("securityRoles", Collections.synchronizedSet(Collections.emptySet()).getClass()), + new ObjectStreamField("requestedTenant", String.class), + new ObjectStreamField("attributes", Collections.synchronizedMap(Collections.emptyMap()).getClass()), + new ObjectStreamField("isInjected", Boolean.TYPE) + }; + + /** + * Creates a backwards compatible object that can be used for serialization + */ + @Serial + private void writeObject(ObjectOutputStream out) + throws IOException { + ObjectOutputStream.PutField fields = out.putFields(); + fields.put("name", name); + fields.put("roles", Collections.synchronizedSet(new HashSet<>(this.roles))); + fields.put("securityRoles", Collections.synchronizedSet(new HashSet<>(this.securityRoles))); + fields.put("requestedTenant", requestedTenant); + fields.put("attributes", Collections.synchronizedMap(new HashMap<>(this.attributes))); + fields.put("isInjected", this.isInjected); + + out.writeFields(); + } } diff --git a/src/main/java/org/opensearch/security/user/UserFactory.java b/src/main/java/org/opensearch/security/user/UserFactory.java new file mode 100644 index 0000000000..d3f8328a7e --- /dev/null +++ b/src/main/java/org/opensearch/security/user/UserFactory.java @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ +package org.opensearch.security.user; + +import java.time.Duration; +import java.util.concurrent.ExecutionException; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +/** + * Infrastructure to create user objects. This class has two implementations: + *
    + *
  • Caching: Keeps a serialized to unserialized cache and thus speeds up incoming request by making deserialization unnecessary
  • + *
  • Simple: This implementation does not keep a cache. This can be used for unit testing, where no cache is necessary.
  • + *
+ */ +public abstract class UserFactory { + public abstract User fromSerializedBase64(String serializedBase64); + + public static class Simple extends UserFactory { + + @Override + public User fromSerializedBase64(String serializedBase64) { + return User.fromSerializedBase64(serializedBase64); + } + } + + public static class Caching extends UserFactory { + private final Cache serializedBase64ToUserCache; + + public Caching() { + this.serializedBase64ToUserCache = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofHours(1)).build(); + } + + public User fromSerializedBase64(String serializedBase64) { + try { + return serializedBase64ToUserCache.get(serializedBase64, () -> User.fromSerializedBase64(serializedBase64)); + } catch (ExecutionException e) { + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } else { + throw new RuntimeException(e); + } + } + } + } +} diff --git a/src/main/java/org/opensearch/security/user/serialized/User.java b/src/main/java/org/opensearch/security/user/serialized/User.java new file mode 100644 index 0000000000..40518ec903 --- /dev/null +++ b/src/main/java/org/opensearch/security/user/serialized/User.java @@ -0,0 +1,69 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ +package org.opensearch.security.user.serialized; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +/** + * This class is used for making sure that the serialized format of this User object is identical to the + * serialized format of the User object from previous OpenSearch versions. + *

+ * It is a weird property of the Java serialization mechanism that it is possible to change the resolved class in + * ObjectInput stream, but only as long as the class name (without package name) stays the same. So, unfortunately, + * this class needs to be named "User". + */ +public class User implements Serializable { + private static final long serialVersionUID = -5500938501822658596L; + private String name; + private Set roles = Collections.synchronizedSet(new HashSet()); + private Set securityRoles = Collections.synchronizedSet(new HashSet()); + private String requestedTenant; + private Map attributes = Collections.synchronizedMap(new HashMap<>()); + private boolean isInjected = false; + + /** + * Converts this objects back to User, just after deserialization + */ + Object readResolve() { + return new org.opensearch.security.user.User( + this.name, + resolve(this.roles), + resolve(this.securityRoles), + this.requestedTenant, + resolve(this.attributes), + this.isInjected + ); + } + + private static ImmutableSet resolve(Set set) { + if (set == null || set.isEmpty()) { + return ImmutableSet.of(); + } else { + return ImmutableSet.copyOf(set); + } + } + + private static ImmutableMap resolve(Map map) { + if (map == null || map.isEmpty()) { + return ImmutableMap.of(); + } else { + return ImmutableMap.copyOf(map); + } + } +} diff --git a/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java b/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java index 3c4e55ca16..16675cbd9e 100644 --- a/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java +++ b/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java @@ -16,6 +16,8 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -80,13 +82,17 @@ public void testHashActionWithValidUserValidPassword() { when(internalUsersModel.getHash(validUsernameAuth.getUsername())).thenReturn(hash); when(internalUsersModel.exists(validUsernameAuth.getUsername())).thenReturn(true); + when(internalUsersModel.getAttributes(validUsernameAuth.getUsername())).thenReturn(ImmutableMap.of()); + when(internalUsersModel.getSecurityRoles(validUsernameAuth.getUsername())).thenReturn(ImmutableSet.of()); + when(internalUsersModel.getBackendRoles(validUsernameAuth.getUsername())).thenReturn(ImmutableSet.of()); + doReturn(true).when(internalAuthenticationBackend).passwordMatchesHash(Mockito.any(String.class), Mockito.any(char[].class)); // Act internalAuthenticationBackend.authenticate(validUsernameAuth); verify(internalAuthenticationBackend, times(1)).passwordMatchesHash(hash, array); - verify(internalUsersModel, times(1)).getBackenRoles(validUsernameAuth.getUsername()); + verify(internalUsersModel, times(1)).getBackendRoles(validUsernameAuth.getUsername()); } @Test diff --git a/src/test/java/org/opensearch/security/auth/UserInjectorTest.java b/src/test/java/org/opensearch/security/auth/UserInjectorTest.java index 74b48d54e5..006438cb4a 100644 --- a/src/test/java/org/opensearch/security/auth/UserInjectorTest.java +++ b/src/test/java/org/opensearch/security/auth/UserInjectorTest.java @@ -23,7 +23,6 @@ import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.http.XFFResolver; import org.opensearch.security.support.ConfigConstants; -import org.opensearch.security.user.User; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportRequest; @@ -60,9 +59,9 @@ public void testValidInjectUser() { HashSet roles = new HashSet<>(); roles.addAll(Arrays.asList("role1", "role2")); threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "user|role1,role2"); - User injectedUser = userInjector.getInjectedUser(); - assertThat("user", is(injectedUser.getName())); - assertThat(roles, is(injectedUser.getRoles())); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); + assertThat("user", is(injectedUser.getUser().getName())); + assertThat(roles, is(injectedUser.getUser().getRoles())); } @Test @@ -73,8 +72,8 @@ public void testValidInjectUserIpV6() { ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "user|role1,role2|2001:db8:3333:4444:5555:6666:7777:8888:9200" ); - UserInjector.InjectedUser injectedUser = userInjector.getInjectedUser(); - assertThat(injectedUser.getName(), is("user")); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); + assertThat(injectedUser.getUser().getName(), is("user")); assertThat(injectedUser.getTransportAddress().getPort(), is(9200)); assertThat(injectedUser.getTransportAddress().getAddress(), is("2001:db8:3333:4444:5555:6666:7777:8888")); } @@ -84,8 +83,8 @@ public void testValidInjectUserIpV6ShortFormat() { HashSet roles = new HashSet<>(); roles.addAll(Arrays.asList("role1", "role2")); threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "user|role1,role2|2001:db8::1:9200"); - UserInjector.InjectedUser injectedUser = userInjector.getInjectedUser(); - assertThat(injectedUser.getName(), is("user")); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); + assertThat(injectedUser.getUser().getName(), is("user")); assertThat(injectedUser.getTransportAddress().getPort(), is(9200)); assertThat(injectedUser.getTransportAddress().getAddress(), is("2001:db8::1")); } @@ -98,7 +97,7 @@ public void testInvalidInjectUserIpV6() { ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "user|role1,role2|2001:db8:3333:5555:6666:7777:8888:9200" ); - User injectedUser = userInjector.getInjectedUser(); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); assertNull(injectedUser); } @@ -110,9 +109,9 @@ public void testValidInjectUserBracketsIpV6() { ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "user|role1,role2|[2001:db8:3333:4444:5555:6666:7777:8888]:9200" ); - UserInjector.InjectedUser injectedUser = userInjector.getInjectedUser(); - assertThat(injectedUser.getName(), is("user")); - assertThat(injectedUser.getRoles(), is(roles)); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); + assertThat(injectedUser.getUser().getName(), is("user")); + assertThat(injectedUser.getUser().getRoles(), is(roles)); assertThat(injectedUser.getTransportAddress().getPort(), is(9200)); assertThat(injectedUser.getTransportAddress().getAddress(), is("2001:db8:3333:4444:5555:6666:7777:8888")); } @@ -122,13 +121,13 @@ public void testInvalidInjectUser() { HashSet roles = new HashSet<>(); roles.addAll(Arrays.asList("role1", "role2")); threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, "|role1,role2"); - User injectedUser = userInjector.getInjectedUser(); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); assertNull(injectedUser); } @Test public void testEmptyInjectUserHeader() { - User injectedUser = userInjector.getInjectedUser(); + UserInjector.Result injectedUser = userInjector.getInjectedUser(); assertNull(injectedUser); } diff --git a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java index 553befc5a6..6667ceb8c6 100755 --- a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java +++ b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java @@ -366,8 +366,8 @@ public void testLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend lbe = new LDAPAuthenticationBackend(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -384,17 +384,18 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + User user = new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + assertThat(((LdapUser) user).getUserEntry().getDn(), is(user.getName())); + + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); MatcherAssert.assertThat(user.getRoles(), hasItem("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); } @Test @@ -410,12 +411,10 @@ public void testLdapAuthenticationReturnAttributes() throws Exception { .putList(ConfigConstants.LDAP_RETURN_ATTRIBUTES, "mail", "cn", "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); - final String[] attributes = user.getUserEntry().getAttributeNames(); Assert.assertNotNull(user); @@ -485,10 +484,10 @@ public void testLdapEscape() throws Exception { ); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); - assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - assertThat(user.getRoles().size(), is(4)); - Assert.assertTrue(user.getRoles().toString().contains("ceo")); + User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + assertThat(userWithRoles.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); + assertThat(userWithRoles.getRoles().size(), is(4)); + Assert.assertTrue(userWithRoles.getRoles().toString().contains("ceo")); } @Test @@ -507,13 +506,13 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getOriginalUsername(), is("Michael Jackson")); assertThat(user.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); - assertThat(user.getRoles().size(), is(2)); - MatcherAssert.assertThat(user.getRoles(), hasItem("ceo")); + assertThat(userWithRoles.getRoles().size(), is(2)); + MatcherAssert.assertThat(userWithRoles.getRoles(), hasItem("ceo")); assertThat(user.getUserEntry().getDn(), is(user.getName())); } @@ -529,9 +528,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -551,9 +548,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -574,9 +569,7 @@ public void testLdapAuthorizationNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -600,7 +593,7 @@ public void testLdapNestedRoleFiltering() { final User user = new User("spock"); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -626,9 +619,7 @@ public void testLdapNestedRoleFilteringWithExcludedRolesWildcard() { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("nested*")) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -654,9 +645,7 @@ public void testLdapdRoleFiltering() { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("ceo", "role1", "role2")) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -682,9 +671,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -706,9 +693,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -730,9 +715,9 @@ public void testLdapAuthorizationDn() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -792,16 +777,16 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -817,16 +802,16 @@ public void testLdapAuthorizationSkipUsersNoDn() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "jacksonm") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -844,9 +829,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -871,9 +854,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -899,9 +880,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -925,9 +904,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -950,9 +927,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -1021,9 +996,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("nondnroles"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -1051,25 +1024,25 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1077,7 +1050,7 @@ public void testLdapSpecial186() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1099,25 +1072,25 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1125,7 +1098,7 @@ public void testLdapSpecial186_2() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); diff --git a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java index c5e70a68dc..fdcc34dc77 100644 --- a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java +++ b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java @@ -367,8 +367,8 @@ public void testLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend lbe = new LDAPAuthenticationBackend(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -385,17 +385,17 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -454,12 +454,12 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + User user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) ); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -477,18 +477,18 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put("roles.g1.search", "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); - assertThat(user.getOriginalUsername(), is("Michael Jackson")); - assertThat(user.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); + assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); MatcherAssert.assertThat(user.getRoles(), hasItem("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -503,9 +503,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -526,9 +524,7 @@ public void testLdapAuthorizationNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -550,9 +546,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -574,9 +568,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -598,9 +590,9 @@ public void testLdapAuthorizationDn() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -660,16 +652,16 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -687,9 +679,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -714,9 +704,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -742,9 +730,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -769,9 +755,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -794,9 +778,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -862,9 +844,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("nondnroles"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -946,9 +926,9 @@ public void testChainedLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend lbe = new LDAPAuthenticationBackend(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertTrue(lbe.exists(new User("presleye"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertTrue(lbe.impersonate(new User("presleye")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -965,11 +945,11 @@ public void testChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -979,7 +959,7 @@ public void testChainedLdapAuthorization() throws Exception { Assert.assertTrue(user.getRoles().contains("king")); Assert.assertTrue(user.getRoles().contains("role2")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -996,11 +976,11 @@ public void testCrossChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("mercuryf", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Freddy Mercury,ou=people2,o=TEST")); diff --git a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java index 56dfd2bd09..2ac1dfc9c5 100644 --- a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java +++ b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java @@ -126,7 +126,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; @SuppressWarnings("unused") - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) ); } @@ -388,8 +388,8 @@ public void testLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend2 lbe = new LDAPAuthenticationBackend2(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -405,17 +405,17 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -430,13 +430,13 @@ public void testLdapAuthorizationReturnAttributes() throws Exception { .putList(ConfigConstants.LDAP_RETURN_ATTRIBUTES, "mail", "cn", "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend2(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(ldapUser, null); - final String[] attributes = user.getUserEntry().getAttributeNames(); + final String[] attributes = ldapUser.getUserEntry().getAttributeNames(); Assert.assertNotNull(user); assertThat(attributes.length, is(3)); @@ -500,12 +500,12 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -522,18 +522,18 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put("roles.g1.search", "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); - assertThat(user.getOriginalUsername(), is("Michael Jackson")); - assertThat(user.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); + assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -547,9 +547,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -570,9 +568,7 @@ public void testLdapAuthorizationNested() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("nested2")) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend2(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -594,9 +590,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -617,9 +611,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -640,9 +632,9 @@ public void testLdapAuthorizationDn() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -699,16 +691,16 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -725,9 +717,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -751,9 +741,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -778,9 +766,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -803,9 +789,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -827,9 +811,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -894,9 +876,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("nondnroles"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -974,9 +954,9 @@ public void testChainedLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend2 lbe = new LDAPAuthenticationBackend2(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertTrue(lbe.exists(new User("presleye"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertTrue(lbe.impersonate(new User("presleye")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -992,11 +972,11 @@ public void testChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -1006,7 +986,7 @@ public void testChainedLdapAuthorization() throws Exception { Assert.assertTrue(user.getRoles().contains("king")); Assert.assertTrue(user.getRoles().contains("role2")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -1022,11 +1002,11 @@ public void testCrossChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("mercuryf", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Freddy Mercury,ou=people2,o=TEST")); @@ -1048,9 +1028,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend2(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -1071,25 +1049,25 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1097,7 +1075,7 @@ public void testLdapSpecial186() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1119,25 +1097,25 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1145,7 +1123,7 @@ public void testLdapSpecial186_2() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); diff --git a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java index fd5beec5cd..9cc10ce15e 100755 --- a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java +++ b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java @@ -142,7 +142,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; @SuppressWarnings("unused") - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) ); } @@ -435,8 +435,8 @@ public void testLdapExists() throws Exception { .build(); final LDAPAuthenticationBackend2 lbe = new LDAPAuthenticationBackend2(settings, null); - Assert.assertTrue(lbe.exists(new User("jacksonm"))); - Assert.assertFalse(lbe.exists(new User("doesnotexist"))); + Assert.assertTrue(lbe.impersonate(new User("jacksonm")).isPresent()); + Assert.assertFalse(lbe.impersonate(new User("doesnotexist")).isPresent()); } @Test @@ -452,17 +452,17 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -479,17 +479,17 @@ public void testLdapAuthorizationPooled() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -547,12 +547,12 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -569,18 +569,18 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); - assertThat(user.getOriginalUsername(), is("Michael Jackson")); - assertThat(user.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); + assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -594,9 +594,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -616,9 +614,7 @@ public void testLdapAuthorizationNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -639,9 +635,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -662,9 +656,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -685,9 +677,11 @@ public void testLdapAuthorizationDn() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); + final User ldapUser = new LDAPAuthenticationBackend2(settings, null).authenticate( + new AuthCredentials("jacksonm", "secret".getBytes()) + ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -744,16 +738,16 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) ); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -770,9 +764,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -796,9 +788,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -823,9 +813,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -849,9 +837,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -873,9 +859,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - final User user = new User("spock"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -937,9 +921,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - final User user = new User("nondnroles"); - - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -966,9 +948,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User user = new User("jacksonm"); - - new LDAPAuthorizationBackend2(settings, null).fillRoles(user, null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), null); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -989,25 +969,25 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1015,7 +995,7 @@ public void testLdapSpecial186() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1037,25 +1017,25 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( + final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) ); - Assert.assertNotNull(user); - assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(user.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(user, null); + Assert.assertNotNull(ldapUser); + assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); @@ -1063,7 +1043,7 @@ public void testLdapSpecial186_2() throws Exception { Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - new LDAPAuthorizationBackend(settings, null).fillRoles( + user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), null ); diff --git a/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java b/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java index 5e7980f431..662d296135 100644 --- a/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java +++ b/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java @@ -12,14 +12,16 @@ package org.opensearch.security.cache; import java.nio.file.Path; +import java.util.Optional; import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -public class DummyAuthenticationBackend implements AuthenticationBackend { +public class DummyAuthenticationBackend implements AuthenticationBackend, ImpersonationBackend { private static volatile long authCount; private static volatile long existsCount; @@ -38,9 +40,9 @@ public User authenticate(AuthCredentials credentials) throws OpenSearchSecurityE } @Override - public boolean exists(User user) { + public Optional impersonate(User user) { existsCount++; - return true; + return Optional.of(user); } public static long getAuthCount() { @@ -55,4 +57,5 @@ public static void reset() { authCount = 0; existsCount = 0; } + } diff --git a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java index 8f8a507cb8..793f707ca2 100644 --- a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java +++ b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java @@ -31,10 +31,9 @@ public String getType() { } @Override - public void fillRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { + public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { count++; - user.addRole("role_" + user.getName() + "_" + System.currentTimeMillis() + "_" + count); - + return user.withRole("role_" + user.getName() + "_" + System.currentTimeMillis() + "_" + count); } public static long getCount() { diff --git a/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java b/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java index 878033fd5c..aaeeb59ce9 100644 --- a/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java +++ b/src/test/java/org/opensearch/security/privileges/SystemIndexAccessEvaluatorTest.java @@ -134,8 +134,7 @@ public void setup( } // create a user and associate them with the role - user = new User("user_a"); - user.addSecurityRoles(List.of("role_a")); + user = new User("user_a").withSecurityRoles(List.of("role_a")); // when trying to resolve Index Names diff --git a/src/test/java/org/opensearch/security/support/Base64HelperTest.java b/src/test/java/org/opensearch/security/support/Base64HelperTest.java index b350a6b543..5c1b6667ab 100644 --- a/src/test/java/org/opensearch/security/support/Base64HelperTest.java +++ b/src/test/java/org/opensearch/security/support/Base64HelperTest.java @@ -19,18 +19,12 @@ import java.util.stream.IntStream; import com.google.common.io.BaseEncoding; -import org.junit.Assert; import org.junit.Test; import org.opensearch.OpenSearchException; import org.opensearch.action.search.SearchRequest; -import org.opensearch.security.auth.UserInjector; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; -import org.ldaptive.LdapEntry; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; @@ -118,30 +112,6 @@ public void notSafeDeserializable() throws Exception { assertThat(exception.getMessage(), containsString("Unauthorized deserialization attempt")); } - @Test - public void testLdapUser() { - LdapUser ldapUser = new LdapUser( - "username", - "originalusername", - new LdapEntry("dn"), - new AuthCredentials("originalusername", "12345"), - 34, - WildcardMatcher.ANY - ); - assertThat(ds(ldapUser), is(ldapUser)); - } - - @Test - public void testInjectedUser() { - UserInjector.InjectedUser injectedUser = new UserInjector.InjectedUser("username"); - - // we expect to get User object when deserializing InjectedUser via JDK serialization - User user = new User("username"); - User deserializedUser = (User) ds(injectedUser); - assertThat(deserializedUser, is(user)); - Assert.assertTrue(deserializedUser.isInjected()); - } - /** * Just one sanity test comprising invocation of JDK and Custom Serialization. * diff --git a/src/test/java/org/opensearch/security/support/SafeSerializationUtilsTest.java b/src/test/java/org/opensearch/security/support/SafeSerializationUtilsTest.java index 187fd8b372..8f5cab1743 100644 --- a/src/test/java/org/opensearch/security/support/SafeSerializationUtilsTest.java +++ b/src/test/java/org/opensearch/security/support/SafeSerializationUtilsTest.java @@ -20,7 +20,6 @@ import org.junit.After; import org.junit.Test; -import org.opensearch.security.auth.UserInjector; import org.opensearch.security.user.User; import com.amazon.dlic.auth.ldap.LdapUser; @@ -47,7 +46,6 @@ public void testSafeClasses() { assertTrue(SafeSerializationUtils.isSafeClass(InetSocketAddress.class)); assertTrue(SafeSerializationUtils.isSafeClass(Pattern.class)); assertTrue(SafeSerializationUtils.isSafeClass(User.class)); - assertTrue(SafeSerializationUtils.isSafeClass(UserInjector.InjectedUser.class)); assertTrue(SafeSerializationUtils.isSafeClass(SourceFieldsContext.class)); assertTrue(SafeSerializationUtils.isSafeClass(LdapUser.class)); assertTrue(SafeSerializationUtils.isSafeClass(SearchEntry.class)); diff --git a/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java b/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java index 2443abb7e8..a1396ff980 100644 --- a/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java +++ b/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java @@ -40,6 +40,7 @@ import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; +import org.opensearch.security.user.UserFactory; import org.opensearch.telemetry.tracing.noop.NoopTracer; import org.opensearch.test.transport.MockTransport; import org.opensearch.threadpool.ThreadPool; @@ -148,7 +149,8 @@ public void setup() { sslExceptionHandler, clusterInfoHolder, sslConfig, - () -> true + () -> true, + new UserFactory.Simple() ); clusterName = ClusterName.DEFAULT; From b865bce0bf9ab9a54baa3c2a595ed189023b1e27 Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Tue, 13 May 2025 11:51:40 +0200 Subject: [PATCH 2/6] Made LdapUser class unneccessary by introducing AuthenticationContext Signed-off-by: Nils Bandener --- .../opensearch/security/user/UserTest.java | 27 +- .../com/amazon/dlic/auth/ldap/LdapUser.java | 94 ++----- .../security/auth/AuthenticationBackend.java | 5 +- .../security/auth/AuthenticationContext.java | 48 ++++ .../security/auth/AuthorizationBackend.java | 5 +- .../security/auth/BackendRegistry.java | 22 +- .../InternalAuthenticationBackend.java | 6 +- .../internal/NoOpAuthenticationBackend.java | 4 +- .../internal/NoOpAuthorizationBackend.java | 4 +- .../backend/LDAPAuthenticationBackend.java | 71 +++-- .../backend/LDAPAuthorizationBackend.java | 26 +- .../ldap2/LDAPAuthenticationBackend2.java | 43 +-- .../auth/ldap2/LDAPAuthorizationBackend2.java | 16 +- .../org/opensearch/security/user/User.java | 17 +- .../security/user/serialized/User.java | 2 +- .../auth/InternalAuthBackendTests.java | 8 +- .../security/auth/ldap/LdapBackendTest.java | 233 +++++++---------- .../auth/ldap/LdapBackendTestClientCert.java | 46 ++-- .../ldap/LdapBackendTestNewStyleConfig.java | 186 +++++-------- .../ldap2/LdapBackendTestClientCert2.java | 46 ++-- .../ldap2/LdapBackendTestNewStyleConfig2.java | 246 +++++++----------- .../ldap2/LdapBackendTestOldStyleConfig2.java | 230 +++++++--------- .../cache/DummyAuthenticationBackend.java | 6 +- .../security/cache/DummyAuthorizer.java | 4 +- 24 files changed, 622 insertions(+), 773 deletions(-) create mode 100644 src/main/java/org/opensearch/security/auth/AuthenticationContext.java diff --git a/src/integrationTest/java/org/opensearch/security/user/UserTest.java b/src/integrationTest/java/org/opensearch/security/user/UserTest.java index 2e9ed0ab77..8a8c104e05 100644 --- a/src/integrationTest/java/org/opensearch/security/user/UserTest.java +++ b/src/integrationTest/java/org/opensearch/security/user/UserTest.java @@ -39,7 +39,7 @@ public void deserializationFrom2_19() { // user.addRoles(Arrays.asList("br1", "br2", "br3")); // user.addSecurityRoles(Arrays.asList("sr1", "sr2")); // user.addAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")); - // System.out.println(Base64JDKHelper.serializeObject(user)); + // println(Base64JDKHelper.serializeObject(user)); String serialized = "rO0ABXNyACFvcmcub3BlbnNlYXJjaC5zZWN1cml0eS51c2VyLlVzZXKzqL2T65dH3AIABloACmlzSW5qZWN0ZWRMAAphdHRyaWJ1dGVzdAAPTGphdmEvdXRpbC9NYXA7TAAEbmFtZXQAEkxqYXZhL2xhbmcvU3RyaW5nO0wAD3JlcXVlc3RlZFRlbmFudHEAfgACTAAFcm9sZXN0AA9MamF2YS91dGlsL1NldDtMAA1zZWN1cml0eVJvbGVzcQB+AAN4cABzcgAlamF2YS51dGlsLkNvbGxlY3Rpb25zJFN5bmNocm9uaXplZE1hcBtz+QlLSzl7AwACTAABbXEAfgABTAAFbXV0ZXh0ABJMamF2YS9sYW5nL09iamVjdDt4cHNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAN3CAAAAAQAAAACdAABYXQAA3ZfYXQAAWJ0AAN2X2J4cQB+AAd4dAAXc2VyaWFsaXphdGlvbl90ZXN0X3VzZXJwc3IAJWphdmEudXRpbC5Db2xsZWN0aW9ucyRTeW5jaHJvbml6ZWRTZXQGw8J5Au7fPAIAAHhyACxqYXZhLnV0aWwuQ29sbGVjdGlvbnMkU3luY2hyb25pemVkQ29sbGVjdGlvbiph+E0JnJm1AwACTAABY3QAFkxqYXZhL3V0aWwvQ29sbGVjdGlvbjtMAAVtdXRleHEAfgAGeHBzcgARamF2YS51dGlsLkhhc2hTZXS6RIWVlri3NAMAAHhwdwwAAAAQP0AAAAAAAAN0AANicjF0AANicjN0AANicjJ4cQB+ABJ4c3EAfgAPc3EAfgATdwwAAAAQP0AAAAAAAAJ0AANzcjJ0AANzcjF4cQB+ABh4"; @@ -51,4 +51,29 @@ public void deserializationFrom2_19() { user ); } + + @Test + public void deserializationLdapUserFrom2_19() { + // The following base64 string was produced by the following code on OpenSearch 2.19 + // LdapUser user = new LdapUser("serialization_test_user", + // "original_user_name", + // new LdapEntry("cn=test,ou=people,o=TEST", new LdapAttribute("test_ldap_attr", "test_ldap_attr_value")), + // new AuthCredentials("test_user", "secret".getBytes(StandardCharsets.UTF_8)), + // 100, + // WildcardMatcher.ANY); + // user.addRoles(Arrays.asList("br1", "br2", "br3")); + // user.addSecurityRoles(Arrays.asList("sr1", "sr2")); + // user.addAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")); + // println(Base64JDKHelper.serializeObject(user)); + String serialized = + "rO0ABXNyACJjb20uYW1hem9uLmRsaWMuYXV0aC5sZGFwLkxkYXBVc2VyAAAAAAAAAAECAAFMABBvcmlnaW5hbFVzZXJuYW1ldAASTGphdmEvbGFuZy9TdHJpbmc7eHIAIW9yZy5vcGVuc2VhcmNoLnNlY3VyaXR5LnVzZXIuVXNlcrOovZPrl0fcAgAGWgAKaXNJbmplY3RlZEwACmF0dHJpYnV0ZXN0AA9MamF2YS91dGlsL01hcDtMAARuYW1lcQB+AAFMAA9yZXF1ZXN0ZWRUZW5hbnRxAH4AAUwABXJvbGVzdAAPTGphdmEvdXRpbC9TZXQ7TAANc2VjdXJpdHlSb2xlc3EAfgAEeHAAc3IAJWphdmEudXRpbC5Db2xsZWN0aW9ucyRTeW5jaHJvbml6ZWRNYXAbc/kJS0s5ewMAAkwAAW1xAH4AA0wABW11dGV4dAASTGphdmEvbGFuZy9PYmplY3Q7eHBzcgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAGdwgAAAAIAAAABXQAB2xkYXAuZG50ABhjbj10ZXN0LG91PXBlb3BsZSxvPVRFU1R0AAFhdAADdl9hdAAYYXR0ci5sZGFwLnRlc3RfbGRhcF9hdHRydAAUdGVzdF9sZGFwX2F0dHJfdmFsdWV0AAFidAADdl9idAAWbGRhcC5vcmlnaW5hbC51c2VybmFtZXQAEm9yaWdpbmFsX3VzZXJfbmFtZXhxAH4ACHh0ABdzZXJpYWxpemF0aW9uX3Rlc3RfdXNlcnBzcgAlamF2YS51dGlsLkNvbGxlY3Rpb25zJFN5bmNocm9uaXplZFNldAbDwnkC7t88AgAAeHIALGphdmEudXRpbC5Db2xsZWN0aW9ucyRTeW5jaHJvbml6ZWRDb2xsZWN0aW9uKmH4TQmcmbUDAAJMAAFjdAAWTGphdmEvdXRpbC9Db2xsZWN0aW9uO0wABW11dGV4cQB+AAd4cHNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAABA/QAAAAAAAA3QAA2JyMXQAA2JyM3QAA2JyMnhxAH4AGXhzcQB+ABZzcQB+ABp3DAAAABA/QAAAAAAAAnQAA3NyMnQAA3NyMXhxAH4AH3hxAH4AFA=="; + + User user = User.fromSerializedBase64(serialized); + assertEquals( + new User("serialization_test_user").withRoles(Arrays.asList("br1", "br2", "br3")) + .withSecurityRoles(Arrays.asList("sr1", "sr2")) + .withAttributes(ImmutableMap.of("a", "v_a", "b", "v_b")), + user + ); + } } diff --git a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java index 47e42e282f..f63ff9ee59 100755 --- a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java +++ b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java @@ -11,96 +11,42 @@ package com.amazon.dlic.auth.ldap; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.google.common.collect.ImmutableSet; - -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.security.auth.ldap.util.Utils; -import org.opensearch.security.support.WildcardMatcher; -import org.opensearch.security.user.AuthCredentials; -import org.opensearch.security.user.User; - -import org.ldaptive.LdapAttribute; -import org.ldaptive.LdapEntry; - /** * This class intentionally remains in the com.amazon.dlic.auth.ldap package * to maintain compatibility with serialization/deserialization in mixed cluster * environments (nodes running different versions). The class is serialized and * passed between nodes, and changing the package would break backward compatibility. * - * Note: This class is planned to be replaced as part of making the User object - * immutable in a future release or reconsidering java serialization. + * This class is only used for deserialization. During deserialization, the readResolve() + * method will automatically convert it to a org.opensearch.security.user.User user object. + * It will never be used for serialization, only the org.opensearch.security.user.User user object + * will be serialized. This is possible because the additional attributes of LdapUser were only + * needed during the auth/auth phase, where no inter-node communication is necessary. Afterwards, + * the user object is never used as LdapUser, but just as a plain User object. + * + * This class can be removed as soon as it is no longer possible that a mixed cluster can contain + * nodes which send serialized LdapUser objects. This will be the case for OpenSearch 4.0. * * @see https://github.com/opensearch-project/security/pull/5223 */ -public class LdapUser extends User { +public class LdapUser extends org.opensearch.security.user.serialized.User { private static final long serialVersionUID = 1L; - private final transient LdapEntry userEntry; private final String originalUsername; - public LdapUser( - final String name, - String originalUsername, - final LdapEntry userEntry, - final AuthCredentials credentials, - int customAttrMaxValueLen, - WildcardMatcher allowlistedCustomLdapAttrMatcher - ) { - super(name, ImmutableSet.of(), credentials); - this.originalUsername = originalUsername; - this.userEntry = userEntry; - Map attributes = getCustomAttributesMap(); - // TODO - attributes.putAll(extractLdapAttributes(originalUsername, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher)); + public LdapUser() { + this.originalUsername = null; } /** - * May return null because ldapEntry is transient - * - * @return ldapEntry or null if object was deserialized + * Converts this objects back to User, just after deserialization. + *

+ * Note: We do not convert back to LdapUser, but just to User. The additional attributes of + * LdapUser were only needed during the auth/auth phase, where no inter-node communication + * is necessary. Afterwards, the user object is never used as LdapUser, but just as a plain User + * object. */ - public LdapEntry getUserEntry() { - return userEntry; - } - - public String getDn() { - return userEntry.getDn(); - } - - public String getOriginalUsername() { - return originalUsername; - } - - public static Map extractLdapAttributes( - String originalUsername, - final LdapEntry userEntry, - int customAttrMaxValueLen, - WildcardMatcher allowlistedCustomLdapAttrMatcher - ) { - Map attributes = new HashMap<>(); - attributes.put("ldap.original.username", originalUsername); - attributes.put("ldap.dn", userEntry.getDn()); - - if (customAttrMaxValueLen > 0) { - for (LdapAttribute attr : userEntry.getAttributes()) { - if (attr != null && !attr.isBinary() && !attr.getName().toLowerCase().contains("password")) { - final String val = Utils.getSingleStringValue(attr); - // only consider attributes which are not binary and where its value is not - // longer than customAttrMaxValueLen characters - if (val != null && val.length() > 0 && val.length() <= customAttrMaxValueLen) { - if (allowlistedCustomLdapAttrMatcher.test(attr.getName())) { - attributes.put("attr.ldap." + attr.getName(), val); - } - } - } - } - } - return Collections.unmodifiableMap(attributes); + protected Object readResolve() { + return super.readResolve(); } } diff --git a/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java index 3d78826614..159f122b2c 100644 --- a/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/AuthenticationBackend.java @@ -59,11 +59,10 @@ public interface AuthenticationBackend { *

* Results of this method are normally cached so that we not need to query the backend for every authentication attempt. *

- * @param The credentials to be validated, never null + * @param context The context of this authentication; contains the auth credentials * @return the authenticated User, never null * @throws OpenSearchSecurityException in case an authentication failure * (when credentials are incorrect, the user does not exist or the backend is not reachable) */ - User authenticate(AuthCredentials credentials) throws OpenSearchSecurityException; - + User authenticate(AuthenticationContext context) throws OpenSearchSecurityException; } diff --git a/src/main/java/org/opensearch/security/auth/AuthenticationContext.java b/src/main/java/org/opensearch/security/auth/AuthenticationContext.java new file mode 100644 index 0000000000..0545e41a34 --- /dev/null +++ b/src/main/java/org/opensearch/security/auth/AuthenticationContext.java @@ -0,0 +1,48 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.auth; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.opensearch.security.user.AuthCredentials; + +/** + * This class allows HTTPAuthenticators and authentication backends to provide context data to authorization backends. + * This is especially useful for siblings of authentication backends and authorization backends (like LDAP authc and + * LDAP authz) to pass data which is specific to the auth type (like the LDAP user entry). + *

+ * This allows to abolish specialized sub-classes of the User object (like LdapUser). + */ +public class AuthenticationContext { + private final AuthCredentials credentials; + private final Map, Object> contextData = new HashMap<>(); + + public AuthenticationContext(AuthCredentials credentials) { + this.credentials = credentials; + } + + public void addContextData(Class contextDataType, T contextDataObject) { + this.contextData.put(contextDataType, contextDataObject); + } + + public Optional getContextData(Class contextDataType) { + @SuppressWarnings("unchecked") + T result = (T) this.contextData.get(contextDataType); + return Optional.ofNullable(result); + } + + public AuthCredentials getCredentials() { + return credentials; + } +} diff --git a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java index 42813aed58..4dfece2cf6 100644 --- a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java @@ -27,7 +27,6 @@ package org.opensearch.security.auth; import org.opensearch.OpenSearchSecurityException; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; /** @@ -60,11 +59,11 @@ public interface AuthorizationBackend { * Add them by calling either {@code user.addRole()} or {@code user.addRoles()} *

* @param user The authenticated user to populate with backend roles, never null - * @param credentials Credentials to authenticate to the authorization backend, maybe null. + * @param context Context data specific to the request that is currently processed. * This parameter is for future usage, currently always empty credentials are passed! * @throws OpenSearchSecurityException in case when the authorization backend cannot be reached * or the {@code credentials} are insufficient to authenticate to the authorization backend. */ - User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException; + User addRoles(User user, AuthenticationContext context) throws OpenSearchSecurityException; } diff --git a/src/main/java/org/opensearch/security/auth/BackendRegistry.java b/src/main/java/org/opensearch/security/auth/BackendRegistry.java index f5b620ffe4..c3367c9519 100644 --- a/src/main/java/org/opensearch/security/auth/BackendRegistry.java +++ b/src/main/java/org/opensearch/security/auth/BackendRegistry.java @@ -528,7 +528,9 @@ public User call() throws Exception { Optional impersonatedUser = impersonationBackend.impersonate(user); if (impersonatedUser.isPresent()) { - return authz(impersonatedUser.get(), null, authorizers); // no role cache because no miss here in case of noop + AuthenticationContext context = new AuthenticationContext(new AuthCredentials(user.getName())); + return authz(context, impersonatedUser.get(), null, authorizers); // no role cache because no miss here in case of + // noop } if (isDebugEnabled) { @@ -545,7 +547,12 @@ public User call() throws Exception { } } - private User authz(User authenticatedUser, Cache> roleCache, final Set authorizers) { + private User authz( + AuthenticationContext context, + User authenticatedUser, + Cache> roleCache, + final Set authorizers + ) { if (authenticatedUser == null) { return authenticatedUser; @@ -575,7 +582,7 @@ private User authz(User authenticatedUser, Cache> roleCache, f ); } - authenticatedUser = ab.addRoles(authenticatedUser, new AuthCredentials(authenticatedUser.getName())); + authenticatedUser = ab.addRoles(authenticatedUser, context); } catch (Exception e) { log.error("Cannot retrieve roles for {} from {} due to {}", authenticatedUser, ab.getType(), e.toString(), e); } @@ -603,13 +610,16 @@ private User authcz( if (ac == null) { return null; } + + AuthenticationContext context = new AuthenticationContext(ac); + try { // noop backend configured and no authorizers // that mean authc and authz was completely done via HTTP (like JWT or PKI) if (authBackend.getClass() == NoOpAuthenticationBackend.class && authorizers.isEmpty()) { // no cache - return authBackend.authenticate(ac); + return authBackend.authenticate(context); } return cache.get(ac, new Callable() { @@ -622,8 +632,8 @@ public User call() throws Exception { authBackend.getType() ); } - final User authenticatedUser = authBackend.authenticate(ac); - return authz(authenticatedUser, roleCache, authorizers); + final User authenticatedUser = authBackend.authenticate(context); + return authz(context, authenticatedUser, roleCache, authorizers); } }); } catch (Exception e) { diff --git a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java index 4536c92bb0..c3e74a4621 100644 --- a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java @@ -39,6 +39,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.AuthorizationBackend; import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.hasher.PasswordHasher; @@ -98,7 +99,8 @@ public boolean passwordMatchesHash(String hash, char[] array) { } @Override - public User authenticate(final AuthCredentials credentials) { + public User authenticate(AuthenticationContext context) { + AuthCredentials credentials = context.getCredentials(); boolean userExists; @@ -159,7 +161,7 @@ public String getType() { } @Override - public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { + public User addRoles(User user, AuthenticationContext context) throws OpenSearchSecurityException { if (internalUsersModel == null) { throw new OpenSearchSecurityException( "Internal authentication backend not configured. May be OpenSearch Security is not initialized." diff --git a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java index de2a41f6b9..8da074cce9 100644 --- a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java @@ -32,6 +32,7 @@ import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; import org.opensearch.security.auth.AuthenticationContext; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; @@ -48,7 +49,8 @@ public String getType() { } @Override - public User authenticate(final AuthCredentials credentials) { + public User authenticate(AuthenticationContext context) { + AuthCredentials credentials = context.getCredentials(); return new User( credentials.getUsername(), credentials.getBackendRoles(), diff --git a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java index 2cf128fd9a..aec322d5eb 100644 --- a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthorizationBackend.java @@ -29,8 +29,8 @@ import java.nio.file.Path; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.AuthorizationBackend; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; public class NoOpAuthorizationBackend implements AuthorizationBackend { @@ -45,7 +45,7 @@ public String getType() { } @Override - public User addRoles(User user, AuthCredentials credentials) { + public User addRoles(User user, AuthenticationContext context) { return user; } } diff --git a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java index caaf2df72e..17000c7eb2 100755 --- a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthenticationBackend.java @@ -23,6 +23,8 @@ import java.util.Set; import java.util.UUID; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,17 +32,17 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.AuthenticationContext; +import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.LdapHelper; import org.opensearch.security.auth.ldap.util.Utils; -import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.support.WildcardMatcher; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.ConnectionConfig; +import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; import org.ldaptive.ReturnAttributes; import org.ldaptive.SearchFilter; @@ -83,11 +85,11 @@ public LDAPAuthenticationBackend(final Settings settings, final Path configPath) } @Override - public User authenticate(final AuthCredentials credentials) throws OpenSearchSecurityException { + public User authenticate(AuthenticationContext context) throws OpenSearchSecurityException { Connection ldapConnection = null; - final String user = credentials.getUsername(); - byte[] password = credentials.getPassword(); + final String user = context.getCredentials().getUsername(); + byte[] password = context.getCredentials().getPassword(); try { LdapEntry entry; @@ -137,12 +139,20 @@ public User authenticate(final AuthCredentials credentials) throws OpenSearchSec log.debug("Authenticated username {}", username); } + // Make LdapEntry available to authz backends by adding it to the AuthencationContext + context.addContextData(LdapEntry.class, entry); + // by default all ldap attributes which are not binary and with a max value // length of 36 are included in the user object // if the allowlist contains at least one value then all attributes will be // additional check if allowlisted (allowlist can contain wildcard and regex) - return new LdapUser(username, user, entry, credentials, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher); - + ImmutableMap userAttributes = extractLdapAttributes( + user, + entry, + customAttrMaxValueLen, + allowlistedCustomLdapAttrMatcher + ); + return new User(username, ImmutableSet.of(), ImmutableSet.of(), null, userAttributes, false); } catch (final Exception e) { if (log.isDebugEnabled()) { log.debug("Unable to authenticate user due to ", e); @@ -166,10 +176,6 @@ public Optional impersonate(User user) { Connection ldapConnection = null; String userName = user.getName(); - if (user instanceof LdapUser) { - userName = ((LdapUser) user).getUserEntry().getDn(); - } - try { ldapConnection = LDAPAuthorizationBackend.getConnection(settings, configPath); LdapEntry userEntry = exists( @@ -183,9 +189,7 @@ public Optional impersonate(User user) { if (userEntry != null) { return Optional.of( - user.withAttributes( - LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher) - ) + user.withAttributes(extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher)) ); } else { return Optional.empty(); @@ -326,4 +330,41 @@ private static LdapEntry existsSearchingAllBases( return result.iterator().next(); } + /** + * Support functionality to extract user attributes from an LdapEntry object. + *

+ * This functionality makes sure that: + *

    + *
  • The attributes ldap.original.username and ldap.dn are initialized
  • + *
  • Only attributes of a specified max length are considered (in order to limit the size of the user object)
  • + *
  • That only allowlisted attributes are added
  • + *
+ * Originally located in the LdapUser class: https://github.com/nibix/security/blob/5bc2523535228cca9353054970bd8ac040b79023/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java#L84 + */ + public static ImmutableMap extractLdapAttributes( + String originalUsername, + LdapEntry userEntry, + int customAttrMaxValueLen, + WildcardMatcher allowlistedCustomLdapAttrMatcher + ) { + ImmutableMap.Builder attributes = ImmutableMap.builder(); + attributes.put("ldap.original.username", originalUsername); + attributes.put("ldap.dn", userEntry.getDn()); + + if (customAttrMaxValueLen > 0) { + for (LdapAttribute attr : userEntry.getAttributes()) { + if (attr != null && !attr.isBinary() && !attr.getName().toLowerCase().contains("password")) { + final String val = Utils.getSingleStringValue(attr); + // only consider attributes which are not binary and where its value is not + // longer than customAttrMaxValueLen characters + if (val != null && !val.isEmpty() && val.length() <= customAttrMaxValueLen) { + if (allowlistedCustomLdapAttrMatcher.test(attr.getName())) { + attributes.put("attr.ldap." + attr.getName(), val); + } + } + } + } + } + return attributes.build(); + } } diff --git a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java index 58194d04f8..2469cde025 100755 --- a/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/ldap/backend/LDAPAuthorizationBackend.java @@ -46,6 +46,7 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.Strings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.AuthorizationBackend; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.LdapHelper; @@ -53,10 +54,8 @@ import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.support.PemKeyReader; import org.opensearch.security.support.WildcardMatcher; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import io.netty.util.internal.PlatformDependent; import org.ldaptive.BindConnectionInitializer; import org.ldaptive.BindRequest; @@ -686,29 +685,28 @@ private static void configureSSL(final ConnectionConfig config, final Settings s } @Override - public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { + public User addRoles(User user, AuthenticationContext context) throws OpenSearchSecurityException { if (user == null) { return user; } String authenticatedUser; - String originalUserName; - LdapEntry entry = null; - String dn = null; + String originalUserName = context.getCredentials().getUsername(); + LdapEntry entry = context.getContextData(LdapEntry.class).orElse(null); + String dn; final boolean isDebugEnabled = log.isDebugEnabled(); if (isDebugEnabled) { log.debug("DBGTRACE (2): username: {} -> {}", user.getName(), Arrays.toString(user.getName().getBytes(StandardCharsets.UTF_8))); } - if (user instanceof LdapUser) { - entry = ((LdapUser) user).getUserEntry(); - authenticatedUser = entry.getDn(); - originalUserName = ((LdapUser) user).getOriginalUsername(); + if (entry != null) { + dn = entry.getDn(); + authenticatedUser = dn; } else { + dn = null; authenticatedUser = user.getName(); - originalUserName = user.getName(); } if (isDebugEnabled) { @@ -746,7 +744,7 @@ public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSe try { Set additionalRoles = new HashSet<>(); - if (entry == null || dn == null) { + if (dn == null) { connection = getConnection(settings, configPath); @@ -887,6 +885,10 @@ public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSe log.debug("DBGTRACE (8): escapedDn" + escapedDn); } + if (connection == null) { + connection = getConnection(settings, configPath); + } + for (Map.Entry roleSearchSettingsEntry : roleBaseSettings) { Settings roleSearchSettings = roleSearchSettingsEntry.getValue(); diff --git a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java index 2b438cc83b..9cff0498c4 100755 --- a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java +++ b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthenticationBackend2.java @@ -22,6 +22,8 @@ import java.util.Optional; import java.util.UUID; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,16 +31,16 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.ImpersonationBackend; +import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.Utils; import org.opensearch.security.support.WildcardMatcher; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; import org.opensearch.security.util.SettingsBasedSSLConfigurator.SSLConfigException; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.BindRequest; import org.ldaptive.Connection; import org.ldaptive.ConnectionFactory; @@ -60,7 +62,7 @@ public class LDAPAuthenticationBackend2 implements AuthenticationBackend, Impers private ConnectionFactory authConnectionFactory; private LDAPUserSearcher userSearcher; private final int customAttrMaxValueLen; - private final WildcardMatcher whitelistedCustomLdapAttrMatcher; + private final WildcardMatcher allowlistedCustomLdapAttrMatcher; private final String[] returnAttributes; private final boolean shouldFollowReferrals; @@ -83,14 +85,14 @@ public LDAPAuthenticationBackend2(final Settings settings, final Path configPath .toArray(new String[0]); this.shouldFollowReferrals = settings.getAsBoolean(ConfigConstants.FOLLOW_REFERRALS, ConfigConstants.FOLLOW_REFERRALS_DEFAULT); customAttrMaxValueLen = settings.getAsInt(ConfigConstants.LDAP_CUSTOM_ATTR_MAXVAL_LEN, 36); - whitelistedCustomLdapAttrMatcher = WildcardMatcher.from( + allowlistedCustomLdapAttrMatcher = WildcardMatcher.from( settings.getAsList(ConfigConstants.LDAP_CUSTOM_ATTR_WHITELIST, Collections.singletonList("*")) ); } @Override @SuppressWarnings("removal") - public User authenticate(final AuthCredentials credentials) throws OpenSearchSecurityException { + public User authenticate(AuthenticationContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -101,7 +103,7 @@ public User authenticate(final AuthCredentials credentials) throws OpenSearchSec return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public User run() throws Exception { - return authenticate0(credentials); + return authenticate0(context); } }); } catch (PrivilegedActionException e) { @@ -115,11 +117,11 @@ public User run() throws Exception { } } - private User authenticate0(final AuthCredentials credentials) throws OpenSearchSecurityException { + private User authenticate0(AuthenticationContext context) throws OpenSearchSecurityException { Connection ldapConnection = null; - final String user = credentials.getUsername(); - byte[] password = credentials.getPassword(); + final String user = context.getCredentials().getUsername(); + byte[] password = context.getCredentials().getPassword(); try { @@ -165,12 +167,20 @@ private User authenticate0(final AuthCredentials credentials) throws OpenSearchS log.debug("Authenticated username {}", username); } + // Make LdapEntry available to authz backends by adding it to the AuthencationContext + context.addContextData(LdapEntry.class, entry); + // by default all ldap attributes which are not binary and with a max value // length of 36 are included in the user object // if the whitelist contains at least one value then all attributes will be // additional check if whitelisted (whitelist can contain wildcard and regex) - return new LdapUser(username, user, entry, credentials, customAttrMaxValueLen, whitelistedCustomLdapAttrMatcher); - + ImmutableMap userAttributes = LDAPAuthenticationBackend.extractLdapAttributes( + user, + entry, + customAttrMaxValueLen, + allowlistedCustomLdapAttrMatcher + ); + return new User(username, ImmutableSet.of(), ImmutableSet.of(), null, userAttributes, false); } catch (final Exception e) { if (log.isDebugEnabled()) { log.debug("Unable to authenticate user due to ", e); @@ -202,10 +212,6 @@ public Optional impersonate(User user) { Connection ldapConnection = null; String userName = user.getName(); - if (user instanceof LdapUser) { - userName = ((LdapUser) user).getUserEntry().getDn(); - } - try { ldapConnection = this.connectionFactory.getConnection(); ldapConnection.open(); @@ -214,7 +220,12 @@ public Optional impersonate(User user) { if (userEntry != null) { return Optional.of( user.withAttributes( - LdapUser.extractLdapAttributes(userName, userEntry, customAttrMaxValueLen, whitelistedCustomLdapAttrMatcher) + LDAPAuthenticationBackend.extractLdapAttributes( + userName, + userEntry, + customAttrMaxValueLen, + allowlistedCustomLdapAttrMatcher + ) ) ); } else { diff --git a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java index 3526e71e6c..f9495fff42 100755 --- a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java +++ b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java @@ -35,17 +35,16 @@ import org.opensearch.SpecialPermission; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.Strings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.AuthorizationBackend; import org.opensearch.security.auth.Destroyable; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.auth.ldap.util.LdapHelper; import org.opensearch.security.auth.ldap.util.Utils; import org.opensearch.security.support.WildcardMatcher; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; import org.opensearch.security.util.SettingsBasedSSLConfigurator.SSLConfigException; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.ConnectionFactory; import org.ldaptive.LdapAttribute; @@ -124,7 +123,7 @@ private static List> convertOldStyleSettingsToNewSty @SuppressWarnings("removal") @Override - public User addRoles(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { + public User addRoles(final User user, AuthenticationContext context) throws OpenSearchSecurityException { final SecurityManager sm = System.getSecurityManager(); @@ -136,7 +135,7 @@ public User addRoles(final User user, final AuthCredentials optionalAuthCreds) t return AccessController.doPrivileged(new PrivilegedExceptionAction() { @Override public User run() throws Exception { - return addRoles0(user, optionalAuthCreds); + return addRoles0(user, context); } }); } catch (PrivilegedActionException e) { @@ -150,7 +149,7 @@ public User run() throws Exception { } } - private User addRoles0(final User user, final AuthCredentials optionalAuthCreds) throws OpenSearchSecurityException { + private User addRoles0(final User user, AuthenticationContext context) throws OpenSearchSecurityException { if (user == null) { return user; @@ -158,14 +157,13 @@ private User addRoles0(final User user, final AuthCredentials optionalAuthCreds) String authenticatedUser; String originalUserName; - LdapEntry entry = null; + LdapEntry entry = context.getContextData(LdapEntry.class).orElse(null); String dn = null; - if (user instanceof LdapUser) { - entry = ((LdapUser) user).getUserEntry(); + if (entry != null) { dn = entry.getDn(); authenticatedUser = entry.getDn(); - originalUserName = ((LdapUser) user).getOriginalUsername(); + originalUserName = context.getCredentials().getUsername(); } else { authenticatedUser = user.getName(); originalUserName = user.getName(); diff --git a/src/main/java/org/opensearch/security/user/User.java b/src/main/java/org/opensearch/security/user/User.java index 230f78224e..1d283d1522 100644 --- a/src/main/java/org/opensearch/security/user/User.java +++ b/src/main/java/org/opensearch/security/user/User.java @@ -325,7 +325,6 @@ public String toSerializedBase64() { return result; } - void readObject(ObjectInputStream stream) throws InvalidObjectException { // This object is not supposed to directly read in order to keep compatibility with older OpenSearch versions throw new InvalidObjectException("Use org.opensearch.security.user.serialized.User"); @@ -333,20 +332,18 @@ void readObject(ObjectInputStream stream) throws InvalidObjectException { @Serial private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("name", String.class), - new ObjectStreamField("roles", Collections.synchronizedSet(Collections.emptySet()).getClass()), - new ObjectStreamField("securityRoles", Collections.synchronizedSet(Collections.emptySet()).getClass()), - new ObjectStreamField("requestedTenant", String.class), - new ObjectStreamField("attributes", Collections.synchronizedMap(Collections.emptyMap()).getClass()), - new ObjectStreamField("isInjected", Boolean.TYPE) - }; + new ObjectStreamField("name", String.class), + new ObjectStreamField("roles", Collections.synchronizedSet(Collections.emptySet()).getClass()), + new ObjectStreamField("securityRoles", Collections.synchronizedSet(Collections.emptySet()).getClass()), + new ObjectStreamField("requestedTenant", String.class), + new ObjectStreamField("attributes", Collections.synchronizedMap(Collections.emptyMap()).getClass()), + new ObjectStreamField("isInjected", Boolean.TYPE) }; /** * Creates a backwards compatible object that can be used for serialization */ @Serial - private void writeObject(ObjectOutputStream out) - throws IOException { + private void writeObject(ObjectOutputStream out) throws IOException { ObjectOutputStream.PutField fields = out.putFields(); fields.put("name", name); fields.put("roles", Collections.synchronizedSet(new HashSet<>(this.roles))); diff --git a/src/main/java/org/opensearch/security/user/serialized/User.java b/src/main/java/org/opensearch/security/user/serialized/User.java index 40518ec903..ee17d5714b 100644 --- a/src/main/java/org/opensearch/security/user/serialized/User.java +++ b/src/main/java/org/opensearch/security/user/serialized/User.java @@ -40,7 +40,7 @@ public class User implements Serializable { /** * Converts this objects back to User, just after deserialization */ - Object readResolve() { + protected Object readResolve() { return new org.opensearch.security.user.User( this.name, resolve(this.roles), diff --git a/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java b/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java index 16675cbd9e..21cb969522 100644 --- a/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java +++ b/src/test/java/org/opensearch/security/auth/InternalAuthBackendTests.java @@ -89,7 +89,7 @@ public void testHashActionWithValidUserValidPassword() { doReturn(true).when(internalAuthenticationBackend).passwordMatchesHash(Mockito.any(String.class), Mockito.any(char[].class)); // Act - internalAuthenticationBackend.authenticate(validUsernameAuth); + internalAuthenticationBackend.authenticate(new AuthenticationContext(validUsernameAuth)); verify(internalAuthenticationBackend, times(1)).passwordMatchesHash(hash, array); verify(internalUsersModel, times(1)).getBackendRoles(validUsernameAuth.getUsername()); @@ -112,7 +112,7 @@ public void testHashActionWithValidUserInvalidPassword() { OpenSearchSecurityException ex = Assert.assertThrows( OpenSearchSecurityException.class, - () -> internalAuthenticationBackend.authenticate(validUsernameAuth) + () -> internalAuthenticationBackend.authenticate(new AuthenticationContext(validUsernameAuth)) ); assert (ex.getMessage().contains("password does not match")); verify(internalAuthenticationBackend, times(1)).passwordMatchesHash(hash, array); @@ -135,7 +135,7 @@ public void testHashActionWithInvalidUserValidPassword() { OpenSearchSecurityException ex = Assert.assertThrows( OpenSearchSecurityException.class, - () -> internalAuthenticationBackend.authenticate(invalidUsernameAuth) + () -> internalAuthenticationBackend.authenticate(new AuthenticationContext(invalidUsernameAuth)) ); assert (ex.getMessage().contains("not found")); verify(internalAuthenticationBackend, times(1)).passwordMatchesHash(hash, array); @@ -157,7 +157,7 @@ public void testHashActionWithInvalidUserInvalidPassword() { OpenSearchSecurityException ex = Assert.assertThrows( OpenSearchSecurityException.class, - () -> internalAuthenticationBackend.authenticate(invalidUsernameAuth) + () -> internalAuthenticationBackend.authenticate(new AuthenticationContext(invalidUsernameAuth)) ); verify(internalAuthenticationBackend, times(1)).passwordMatchesHash(hash, array); assert (ex.getMessage().contains("not found")); diff --git a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java index 6667ceb8c6..36d3c6b787 100755 --- a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java +++ b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTest.java @@ -24,6 +24,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.backend.LDAPAuthorizationBackend; import org.opensearch.security.auth.ldap.srv.EmbeddedLDAPServer; @@ -34,7 +35,6 @@ import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; @@ -72,9 +72,7 @@ public void testLdapAuthentication() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -88,9 +86,7 @@ public void testLdapAuthenticationFakeLogin() throws Exception { .put(ConfigConstants.LDAP_FAKE_LOGIN_ENABLED, true) .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("unknown", "unknown".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("unknown", "unknown")); } @Test(expected = OpenSearchSecurityException.class) @@ -103,9 +99,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx(injectString, "secret")); } @Test @@ -119,9 +113,7 @@ public void testLdapAuthenticationBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "spocksecret") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -137,9 +129,7 @@ public void testLdapAuthenticationWrongBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "wrong") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } @Test(expected = OpenSearchSecurityException.class) @@ -150,9 +140,7 @@ public void testLdapAuthenticationBindFail() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "wrong".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "wrong")); } @Test(expected = OpenSearchSecurityException.class) @@ -163,9 +151,7 @@ public void testLdapAuthenticationNoUser() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("UNKNOWN", "UNKNOWN".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("UNKNOWN", "UNKNOWN")); } @Test(expected = OpenSearchSecurityException.class) @@ -176,9 +162,7 @@ public void testLdapAuthenticationFail() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "xxxxx".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "xxxxx")); } @Test @@ -196,9 +180,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -218,9 +200,7 @@ public void testLdapAuthenticationSSLPEMFile() throws Exception { .put("path.home", ".") .put("path.conf", FileHelper.getAbsoluteFilePathFromClassPath("ldap/root-ca.pem").getParent()) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, Paths.get("src/test/resources/ldap")).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, Paths.get("src/test/resources/ldap")).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -231,9 +211,7 @@ public void testLdapAuthenticationSSLPEMText() throws Exception { .loadFromPath(Paths.get(FileHelper.getAbsoluteFilePathFromClassPath("ldap/test1.yml").toFile().getAbsolutePath())) .build(); Settings settings = Settings.builder().put(settingsFromFile).putList("hosts", "localhost:" + ldapsPort).build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -255,9 +233,7 @@ public void testLdapAuthenticationSSLSSLv3() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (Exception e) { assertThat(org.ldaptive.LdapException.class, is(e.getCause().getClass())); Assert.assertTrue(e.getCause().getMessage().contains("Unable to connec")); @@ -282,9 +258,7 @@ public void testLdapAuthenticationSSLUnknowCipher() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (Exception e) { assertThat(org.ldaptive.LdapException.class, is(e.getCause().getClass())); Assert.assertTrue(e.getCause().getMessage().contains("Unable to connec")); @@ -309,9 +283,7 @@ public void testLdapAuthenticationSpecialCipherProtocol() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -332,9 +304,7 @@ public void testLdapAuthenticationSSLNoKeystore() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -349,9 +319,7 @@ public void testLdapAuthenticationSSLFailPlain() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (final Exception e) { assertThat(e.getCause().getClass(), is(org.ldaptive.LdapException.class)); } @@ -384,13 +352,12 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - User user = new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); - assertThat(((LdapUser) user).getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); - user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -411,11 +378,10 @@ public void testLdapAuthenticationReturnAttributes() throws Exception { .putList(ConfigConstants.LDAP_RETURN_ATTRIBUTES, "mail", "cn", "uid") .build(); - LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); - final String[] attributes = user.getUserEntry().getAttributeNames(); + final String[] attributes = context.getContextData(LdapEntry.class).orElseThrow().getAttributeNames(); Assert.assertNotNull(user); assertThat(attributes.length, is(3)); @@ -479,12 +445,11 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("ssign", "ssignsecret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(userWithRoles.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(userWithRoles.getRoles().size(), is(4)); Assert.assertTrue(userWithRoles.getRoles().toString().contains("ceo")); @@ -502,18 +467,15 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + AuthenticationContext context = ctx("Michael Jackson", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); - assertThat(user.getOriginalUsername(), is("Michael Jackson")); - assertThat(user.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(userWithRoles.getRoles().size(), is(2)); MatcherAssert.assertThat(userWithRoles.getRoles(), hasItem("ceo")); - assertThat(user.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -528,7 +490,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -548,7 +510,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -569,7 +531,7 @@ public void testLdapAuthorizationNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -591,9 +553,8 @@ public void testLdapNestedRoleFiltering() { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("nested1", "nested2")) .build(); - final User user = new User("spock"); - - User userWithRoles = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + User user = new User("spock"); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -619,7 +580,7 @@ public void testLdapNestedRoleFilteringWithExcludedRolesWildcard() { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("nested*")) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -645,7 +606,7 @@ public void testLdapdRoleFiltering() { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("ceo", "role1", "role2")) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -671,7 +632,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -693,7 +654,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -715,9 +676,9 @@ public void testLdapAuthorizationDn() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - - user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -735,9 +696,7 @@ public void testLdapAuthenticationUserNameAttribute() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERNAME_ATTRIBUTE, "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); } @@ -757,9 +716,7 @@ public void testLdapAuthenticationStartTLS() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -777,16 +734,14 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -802,16 +757,14 @@ public void testLdapAuthorizationSkipUsersNoDn() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "jacksonm") .build(); - LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -829,7 +782,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -854,7 +807,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -880,7 +833,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -904,7 +857,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -927,7 +880,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -944,9 +897,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(16)); @@ -961,9 +912,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_CUSTOM_ATTR_MAXVAL_LEN, 0) .build(); - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -973,9 +922,7 @@ public void testCustomAttributes() throws Exception { .putList(ConfigConstants.LDAP_CUSTOM_ATTR_WHITELIST, "*objectclass*", "entryParentId") .build(); - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -996,7 +943,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), ctx("nondnroles", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -1024,27 +971,29 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), context); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -1052,7 +1001,7 @@ public void testLdapSpecial186() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -1072,27 +1021,29 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), context); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1100,7 +1051,7 @@ public void testLdapSpecial186_2() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1115,11 +1066,10 @@ public void testOperationalAttributes() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); Assert.assertNotNull(user); - LdapAttribute operationAttribute = user.getUserEntry().getAttribute("entryUUID"); + LdapAttribute operationAttribute = context.getContextData(LdapEntry.class).orElseThrow().getAttribute("entryUUID"); Assert.assertNotNull(operationAttribute); Assert.assertNotNull(operationAttribute.getStringValue()); Assert.assertTrue(operationAttribute.getStringValue().length() > 10); @@ -1139,9 +1089,7 @@ public void testMultiCn() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("multi", "multi".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("multi", "multi")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=cabc,ou=people,o=TEST")); } @@ -1155,4 +1103,7 @@ public static void tearDown() throws Exception { } + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestClientCert.java b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestClientCert.java index 7d5cd60bee..b082238e21 100644 --- a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestClientCert.java +++ b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestClientCert.java @@ -22,13 +22,13 @@ import org.junit.Test; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.user.AuthCredentials; - -import com.amazon.dlic.auth.ldap.LdapUser; +import org.opensearch.security.user.User; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -58,11 +58,9 @@ public void testNoAuth() throws Exception { .put("path.home", ".") .build(); - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -91,11 +89,9 @@ public void testNoAuthX() throws Exception { .put("path.home", ".") .build(); - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -124,11 +120,9 @@ public void testNoAuthY() throws Exception { .put("path.home", ".") .build(); - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -158,9 +152,7 @@ public void testBindDnAuthLocalhost() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -187,9 +179,7 @@ public void testLdapSslAuth() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -219,9 +209,7 @@ public void testLdapSslAuthPem() throws Exception { // .put(ConfigConstants.LDAP_PASSWORD, "ldapbinder") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -248,9 +236,7 @@ public void testLdapSslAuthNo() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -283,9 +269,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -311,4 +295,8 @@ public static File getAbsoluteFilePathFromClassPath(final String fileNameFromCla } return null; } + + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java index fdcc34dc77..38ccb35cf0 100644 --- a/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java +++ b/src/test/java/org/opensearch/security/auth/ldap/LdapBackendTestNewStyleConfig.java @@ -24,6 +24,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.backend.LDAPAuthorizationBackend; import org.opensearch.security.auth.ldap.srv.EmbeddedLDAPServer; @@ -34,7 +35,6 @@ import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.LdapEntry; import org.ldaptive.ReturnAttributes; @@ -71,9 +71,7 @@ public void testLdapAuthentication() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -87,9 +85,7 @@ public void testLdapAuthenticationFakeLogin() throws Exception { .put(ConfigConstants.LDAP_FAKE_LOGIN_ENABLED, true) .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("unknown", "unknown".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("unknown", "unknown")); } @Test(expected = OpenSearchSecurityException.class) @@ -103,9 +99,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; @SuppressWarnings("unused") - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx(injectString, "secret")); } @Test @@ -119,9 +113,7 @@ public void testLdapAuthenticationBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "spocksecret") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -137,9 +129,7 @@ public void testLdapAuthenticationWrongBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "wrong") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } @Test(expected = OpenSearchSecurityException.class) @@ -150,9 +140,7 @@ public void testLdapAuthenticationBindFail() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "wrong".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "wrong")); } @Test(expected = OpenSearchSecurityException.class) @@ -163,9 +151,7 @@ public void testLdapAuthenticationNoUser() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("UNKNOWN", "UNKNOWN".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("UNKNOWN", "UNKNOWN")); } @Test(expected = OpenSearchSecurityException.class) @@ -176,9 +162,7 @@ public void testLdapAuthenticationFail() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "xxxxx".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "xxxxx")); } @Test @@ -196,9 +180,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -218,9 +200,7 @@ public void testLdapAuthenticationSSLPEMFile() throws Exception { .put("path.home", ".") .put("path.conf", FileHelper.getAbsoluteFilePathFromClassPath("ldap/root-ca.pem").getParent()) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, Paths.get("src/test/resources/ldap")).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, Paths.get("src/test/resources/ldap")).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -232,9 +212,7 @@ public void testLdapAuthenticationSSLPEMText() throws Exception { .loadFromPath(Paths.get(FileHelper.getAbsoluteFilePathFromClassPath("ldap/test1.yml").toFile().getAbsolutePath())) .build(); Settings settings = Settings.builder().put(settingsFromFile).putList("hosts", "localhost:" + ldapsPort).build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -256,9 +234,7 @@ public void testLdapAuthenticationSSLSSLv3() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (Exception e) { assertThat(org.ldaptive.LdapException.class, is(e.getCause().getClass())); Assert.assertTrue(e.getCause().getMessage().contains("Unable to connec")); @@ -283,9 +259,7 @@ public void testLdapAuthenticationSSLUnknownCipher() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (Exception e) { assertThat(org.ldaptive.LdapException.class, is(e.getCause().getClass())); Assert.assertTrue(e.getCause().getMessage().contains("Unable to connec")); @@ -310,9 +284,7 @@ public void testLdapAuthenticationSpecialCipherProtocol() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -333,9 +305,7 @@ public void testLdapAuthenticationSSLNoKeystore() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -350,9 +320,7 @@ public void testLdapAuthenticationSSLFailPlain() throws Exception { .build(); try { - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); } catch (final Exception e) { assertThat(e.getCause().getClass(), is(org.ldaptive.LdapException.class)); } @@ -385,17 +353,15 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -454,12 +420,11 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - User user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("ssign", "ssignsecret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -477,18 +442,15 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put("roles.g1.search", "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("Michael Jackson", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); - assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); - assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); MatcherAssert.assertThat(user.getRoles(), hasItem("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -503,7 +465,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -524,7 +486,7 @@ public void testLdapAuthorizationNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -546,7 +508,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -568,7 +530,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -590,9 +552,9 @@ public void testLdapAuthorizationDn() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthenticationBackend(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - - user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -610,9 +572,7 @@ public void testLdapAuthenticationUserNameAttribute() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERNAME_ATTRIBUTE, "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); } @@ -632,9 +592,7 @@ public void testLdapAuthenticationStartTLS() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -652,16 +610,14 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -679,7 +635,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -704,7 +660,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -730,7 +686,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -755,7 +711,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -778,7 +734,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -795,9 +751,7 @@ public void testCustomAttributes() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(16)); @@ -809,9 +763,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_CUSTOM_ATTR_MAXVAL_LEN, 0) .build(); - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -821,9 +773,7 @@ public void testCustomAttributes() throws Exception { .putList(ConfigConstants.LDAP_CUSTOM_ATTR_WHITELIST, "*objectclass*", "entryParentId") .build(); - user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -844,7 +794,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), ctx("nondnroles", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -870,9 +820,7 @@ public void testChainedLdapAuthentication1() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -888,9 +836,7 @@ public void testChainedLdapAuthentication2() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("presleye", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(ctx("presleye", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Elvis Presley,ou=people2,o=TEST")); } @@ -907,9 +853,7 @@ public void testChainedLdapAuthenticationDuplicate() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend(settings, null).authenticate(ctx("jacksonm", "secret")); // Fails with OpenSearchSecurityException because two possible instances are // found @@ -945,11 +889,9 @@ public void testChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -959,7 +901,7 @@ public void testChainedLdapAuthorization() throws Exception { Assert.assertTrue(user.getRoles().contains("king")); Assert.assertTrue(user.getRoles().contains("role2")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -976,11 +918,9 @@ public void testCrossChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("mercuryf", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("mercuryf", "secret"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Freddy Mercury,ou=people2,o=TEST")); @@ -998,4 +938,8 @@ public static void tearDown() throws Exception { } } + + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestClientCert2.java b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestClientCert2.java index bc42dce764..d9686ad2e6 100644 --- a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestClientCert2.java +++ b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestClientCert2.java @@ -22,12 +22,12 @@ import org.junit.Test; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.util.ConfigConstants; import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLConfigConstants; import org.opensearch.security.user.AuthCredentials; - -import com.amazon.dlic.auth.ldap.LdapUser; +import org.opensearch.security.user.User; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -58,11 +58,9 @@ public void testNoAuth() throws Exception { .build(); @SuppressWarnings("unused") - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -92,11 +90,9 @@ public void testNoAuthX() throws Exception { .build(); @SuppressWarnings("unused") - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -126,11 +122,9 @@ public void testNoAuthY() throws Exception { .build(); @SuppressWarnings("unused") - LdapUser user; + User user; try { - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.fail(); } catch (Exception e) { Assert.assertTrue( @@ -160,9 +154,7 @@ public void testBindDnAuthLocalhost() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -189,9 +181,7 @@ public void testLdapSslAuth() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -221,9 +211,7 @@ public void testLdapSslAuthPem() throws Exception { // .put(ConfigConstants.LDAP_PASSWORD, "ldapbinder") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -250,9 +238,7 @@ public void testLdapSslAuthNo() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -285,9 +271,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ldap_hr_employee", "ldap_hr_employee".getBytes(StandardCharsets.UTF_8)) - ); + final User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("ldap_hr_employee", "ldap_hr_employee")); Assert.assertNotNull(user); assertThat(user.getName(), is("ldap_hr_employee")); } @@ -313,4 +297,8 @@ public static File getAbsoluteFilePathFromClassPath(final String fileNameFromCla } return null; } + + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java index 2ac1dfc9c5..a04ebe955d 100644 --- a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java +++ b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestNewStyleConfig2.java @@ -31,6 +31,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.backend.LDAPAuthorizationBackend; import org.opensearch.security.auth.ldap.srv.EmbeddedLDAPServer; @@ -42,7 +43,6 @@ import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; @@ -96,9 +96,7 @@ public void testLdapAuthentication() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -111,9 +109,7 @@ public void testLdapAuthenticationFakeLogin() throws Exception { .put(ConfigConstants.LDAP_FAKE_LOGIN_ENABLED, true) .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("unknown", "unknown".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("unknown", "unknown")); } @Test(expected = OpenSearchSecurityException.class) @@ -126,9 +122,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; @SuppressWarnings("unused") - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx(injectString, "secret")); } @Test @@ -141,9 +135,7 @@ public void testLdapAuthenticationBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "spocksecret") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -159,9 +151,7 @@ public void testLdapAuthenticationWrongBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "wrong") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected exception"); } catch (Exception e) { Assert.assertTrue(ExceptionUtils.getStackTrace(e), ExceptionUtils.getStackTrace(e).contains("password was incorrect")); @@ -175,9 +165,7 @@ public void testLdapAuthenticationBindFail() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "wrong".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "wrong")); } @Test(expected = OpenSearchSecurityException.class) @@ -187,9 +175,7 @@ public void testLdapAuthenticationNoUser() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("UNKNOWN", "UNKNOWN".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("UNKNOWN", "UNKNOWN")); } @Test(expected = OpenSearchSecurityException.class) @@ -199,9 +185,7 @@ public void testLdapAuthenticationFail() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "xxxxx".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "xxxxx")); } @Test @@ -218,9 +202,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -239,9 +221,7 @@ public void testLdapAuthenticationSSLPEMFile() throws Exception { .put("path.home", ".") .put("path.conf", FileHelper.getAbsoluteFilePathFromClassPath("ldap/root-ca.pem").getParent()) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, Paths.get("src/test/resources/ldap")).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, Paths.get("src/test/resources/ldap")).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -253,9 +233,7 @@ public void testLdapAuthenticationSSLPEMText() throws Exception { .loadFromPath(Paths.get(FileHelper.getAbsoluteFilePathFromClassPath("ldap/test1.yml").toFile().getAbsolutePath())) .build(); Settings settings = Settings.builder().put(settingsFromFile).putList("hosts", "localhost:" + ldapsPort).build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -276,9 +254,7 @@ public void testLdapAuthenticationSSLSSLv3() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected Exception"); } catch (Exception e) { assertThat(e.getCause().getClass(), is(org.ldaptive.provider.ConnectionException.class)); @@ -303,9 +279,7 @@ public void testLdapAuthenticationSSLUnknownCipher() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected Exception"); } catch (Exception e) { assertThat(e.getCause().getClass(), is(org.ldaptive.provider.ConnectionException.class)); @@ -333,9 +307,7 @@ public void testLdapAuthenticationSpecialCipherProtocol() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -355,9 +327,7 @@ public void testLdapAuthenticationSSLNoKeystore() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -371,9 +341,7 @@ public void testLdapAuthenticationSSLFailPlain() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected exception"); } catch (final Exception e) { assertThat(e.getCause().getClass(), is(IllegalStateException.class)); @@ -405,17 +373,17 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -430,13 +398,12 @@ public void testLdapAuthorizationReturnAttributes() throws Exception { .putList(ConfigConstants.LDAP_RETURN_ATTRIBUTES, "mail", "cn", "uid") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); - User user = new LDAPAuthorizationBackend2(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend2(settings, null).addRoles(user, context); - final String[] attributes = ldapUser.getUserEntry().getAttributeNames(); + final String[] attributes = context.getContextData(LdapEntry.class).orElseThrow().getAttributeNames(); Assert.assertNotNull(user); assertThat(attributes.length, is(3)); @@ -500,12 +467,12 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) - ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("ssign", "ssignsecret"); + + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -522,18 +489,15 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put("roles.g1.search", "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("Michael Jackson", "secret"); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); - assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); - assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); } @Test @@ -547,7 +511,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -568,7 +532,7 @@ public void testLdapAuthorizationNested() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_EXCLUDE_ROLES, List.of("nested2")) .build(); - User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -590,7 +554,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -611,7 +575,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -632,9 +596,9 @@ public void testLdapAuthorizationDn() throws Exception { .put("roles.g1.search", "(uniqueMember={0})") .build(); - User user = new LDAPAuthenticationBackend2(settings, null).authenticate(new AuthCredentials("jacksonm", "secret".getBytes())); - - user = new LDAPAuthorizationBackend(settings, null).addRoles(user, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -651,9 +615,7 @@ public void testLdapAuthenticationUserNameAttribute() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERNAME_ATTRIBUTE, "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); } @@ -672,9 +634,7 @@ public void testLdapAuthenticationStartTLS() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -691,16 +651,15 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -717,7 +676,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -741,7 +700,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -766,7 +725,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -789,7 +748,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -811,7 +770,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -827,9 +786,7 @@ public void testCustomAttributes() throws Exception { .put("users.u1.search", "(uid={0})") .build(); - LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(16)); @@ -843,9 +800,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_CUSTOM_ATTR_MAXVAL_LEN, 0) .build(); - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -854,9 +809,7 @@ public void testCustomAttributes() throws Exception { .putList(ConfigConstants.LDAP_CUSTOM_ATTR_WHITELIST, "*objectclass*", "entryParentId") .build(); - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -876,7 +829,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), ctx("nondnroles", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -901,9 +854,7 @@ public void testChainedLdapAuthentication1() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -918,9 +869,7 @@ public void testChainedLdapAuthentication2() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("presleye", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("presleye", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Elvis Presley,ou=people2,o=TEST")); } @@ -936,9 +885,7 @@ public void testChainedLdapAuthenticationDuplicate() throws Exception { .put("users.u2.base", "ou=people2,o=TEST") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); // Fails with OpenSearchSecurityException because two possible instances are // found @@ -972,11 +919,9 @@ public void testChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -986,7 +931,7 @@ public void testChainedLdapAuthorization() throws Exception { Assert.assertTrue(user.getRoles().contains("king")); Assert.assertTrue(user.getRoles().contains("role2")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -1002,11 +947,9 @@ public void testCrossChainedLdapAuthorization() throws Exception { .put("roles.g2.search", "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("mercuryf", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("mercuryf", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Freddy Mercury,ou=people2,o=TEST")); @@ -1028,7 +971,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -1049,27 +992,29 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), context); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -1077,7 +1022,7 @@ public void testLdapSpecial186() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -1097,27 +1042,29 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), context); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1125,7 +1072,7 @@ public void testLdapSpecial186_2() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1140,11 +1087,10 @@ public void testOperationalAttributes() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); Assert.assertNotNull(user); - LdapAttribute operationAttribute = user.getUserEntry().getAttribute("entryUUID"); + LdapAttribute operationAttribute = context.getContextData(LdapEntry.class).orElseThrow().getAttribute("entryUUID"); Assert.assertNotNull(operationAttribute); Assert.assertNotNull(operationAttribute.getStringValue()); Assert.assertTrue(operationAttribute.getStringValue().length() > 10); @@ -1159,4 +1105,8 @@ public static void tearDown() throws Exception { } } + + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java index 9cc10ce15e..10abeeac75 100755 --- a/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java +++ b/src/test/java/org/opensearch/security/auth/ldap2/LdapBackendTestOldStyleConfig2.java @@ -30,6 +30,7 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ldap.backend.LDAPAuthenticationBackend; import org.opensearch.security.auth.ldap.backend.LDAPAuthorizationBackend; import org.opensearch.security.auth.ldap.srv.EmbeddedLDAPServer; @@ -41,7 +42,6 @@ import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; -import com.amazon.dlic.auth.ldap.LdapUser; import org.ldaptive.Connection; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; @@ -97,9 +97,7 @@ public void testLdapAuthentication() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -112,9 +110,7 @@ public void testLdapAuthenticationPooled() throws Exception { .put(ConfigConstants.LDAP_POOL_ENABLED, true) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -127,9 +123,7 @@ public void testLdapAuthenticationFakeLogin() throws Exception { .put(ConfigConstants.LDAP_FAKE_LOGIN_ENABLED, true) .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("unknown", "unknown".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("unknown", "unknown")); } @Test(expected = OpenSearchSecurityException.class) @@ -142,9 +136,7 @@ public void testLdapInjection() throws Exception { String injectString = "*jack*"; @SuppressWarnings("unused") - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials(injectString, "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx(injectString, "secret")); } @Test @@ -157,9 +149,7 @@ public void testLdapAuthenticationBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "spocksecret") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -174,9 +164,7 @@ public void testLdapAuthenticationWrongBindDn() throws Exception { .put(ConfigConstants.LDAP_PASSWORD, "wrong") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected exception"); } catch (Exception e) { Assert.assertTrue(ExceptionUtils.getStackTrace(e), ExceptionUtils.getStackTrace(e).contains("password was incorrect")); @@ -190,9 +178,7 @@ public void testLdapAuthenticationBindFail() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "wrong".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "wrong")); } @Test(expected = OpenSearchSecurityException.class) @@ -202,9 +188,7 @@ public void testLdapAuthenticationNoUser() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("UNKNOWN", "UNKNOWN".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("UNKNOWN", "UNKNOWN")); } @Test(expected = OpenSearchSecurityException.class) @@ -214,9 +198,7 @@ public void testLdapAuthenticationFail() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "xxxxx".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "xxxxx")); } @Test(expected = OpenSearchSecurityException.class) @@ -227,9 +209,7 @@ public void testLdapAuthenticationFailPooled() throws Exception { .put(ConfigConstants.LDAP_POOL_ENABLED, true) .build(); - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "xxxxx".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "xxxxx")); } @Test @@ -246,9 +226,7 @@ public void testLdapAuthenticationSSL() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -268,9 +246,7 @@ public void testLdapAuthenticationSSLPooled() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -289,9 +265,7 @@ public void testLdapAuthenticationSSLPEMFile() throws Exception { .put("path.home", ".") .put("path.conf", FileHelper.getAbsoluteFilePathFromClassPath("ldap/root-ca.pem").getParent()) .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, Paths.get("src/test/resources/ldap")).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, Paths.get("src/test/resources/ldap")).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -303,9 +277,7 @@ public void testLdapAuthenticationSSLPEMText() throws Exception { .loadFromPath(Paths.get(FileHelper.getAbsoluteFilePathFromClassPath("ldap/test1.yml").toFile().getAbsolutePath())) .build(); Settings settings = Settings.builder().put(settingsFromFile).putList("hosts", "localhost:" + ldapsPort).build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -326,9 +298,7 @@ public void testLdapAuthenticationSSLSSLv3() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected Exception"); } catch (Exception e) { assertThat(e.getCause().getClass(), is(org.ldaptive.provider.ConnectionException.class)); @@ -353,9 +323,7 @@ public void testLdapAuthenticationSSLUnknowCipher() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected Exception"); } catch (Exception e) { assertThat(e.getCause().getClass().toString(), org.ldaptive.provider.ConnectionException.class, is(e.getCause().getClass())); @@ -380,9 +348,7 @@ public void testLdapAuthenticationSpecialCipherProtocol() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); @@ -402,9 +368,7 @@ public void testLdapAuthenticationSSLNoKeystore() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -418,9 +382,7 @@ public void testLdapAuthenticationSSLFailPlain() throws Exception { .build(); try { - new LDAPAuthenticationBackend2(settings, new File("").toPath()).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + new LDAPAuthenticationBackend2(settings, new File("").toPath()).authenticate(ctx("jacksonm", "secret")); Assert.fail("Expected exception"); } catch (final Exception e) { assertThat(e.getCause().getClass(), is(IllegalStateException.class)); @@ -452,17 +414,16 @@ public void testLdapAuthorization() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -479,17 +440,16 @@ public void testLdapAuthorizationPooled() throws Exception { // "(uniqueMember={0})") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -547,12 +507,11 @@ public void testLdapEscape() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("ssign", "ssignsecret".getBytes(StandardCharsets.UTF_8)) - ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("ssign", "ssignsecret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getName(), is("cn=Special\\, Sign,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(4)); Assert.assertTrue(user.getRoles().toString().contains("ceo")); @@ -569,18 +528,15 @@ public void testLdapAuthorizationRoleSearchUsername() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember=cn={1},ou=people,o=TEST)") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("Michael Jackson", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("Michael Jackson", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); - assertThat(ldapUser.getOriginalUsername(), is("Michael Jackson")); - assertThat(ldapUser.getUserEntry().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(2)); assertThat(new ArrayList<>(new TreeSet<>(user.getRoles())).get(0), is("ceo")); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -594,7 +550,7 @@ public void testLdapAuthorizationOnly() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -614,7 +570,7 @@ public void testLdapAuthorizationNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -635,7 +591,7 @@ public void testLdapAuthorizationNestedFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=nested2,ou=groups,o=TEST") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -656,7 +612,7 @@ public void testLdapAuthorizationDnNested() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -677,11 +633,9 @@ public void testLdapAuthorizationDn() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - final User ldapUser = new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes()) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -698,9 +652,7 @@ public void testLdapAuthenticationUserNameAttribute() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERNAME_ATTRIBUTE, "uid") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); } @@ -719,9 +671,7 @@ public void testLdapAuthenticationStartTLS() throws Exception { .put("path.home", ".") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); } @@ -738,16 +688,14 @@ public void testLdapAuthorizationSkipUsers() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_SKIP_USERS, "cn=Michael Jackson,ou*people,o=TEST") .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); - - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getRoles().size(), is(0)); - assertThat(ldapUser.getUserEntry().getDn(), is(user.getName())); + assertThat(context.getContextData(LdapEntry.class).orElseThrow().getDn(), is(user.getName())); } @Test @@ -764,7 +712,7 @@ public void testLdapAuthorizationNestedAttr() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -788,7 +736,7 @@ public void testLdapAuthorizationNestedAttrFilter() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "cn=rolemo4*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -813,7 +761,7 @@ public void testLdapAuthorizationNestedAttrFilterAll() throws Exception { .putList(ConfigConstants.LDAP_AUTHZ_NESTEDROLEFILTER, "*") .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -837,7 +785,7 @@ public void testLdapAuthorizationNestedAttrFilterAllEqualsNestedFalse() throws E .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -859,7 +807,7 @@ public void testLdapAuthorizationNestedAttrNoRoleSearch() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, false) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spock"), ctx("spock", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("spock")); @@ -875,9 +823,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("cn=Michael Jackson,ou=people,o=TEST")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(16)); @@ -888,9 +834,7 @@ public void testCustomAttributes() throws Exception { .put(ConfigConstants.LDAP_CUSTOM_ATTR_MAXVAL_LEN, 0) .build(); - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -899,9 +843,7 @@ public void testCustomAttributes() throws Exception { .putList(ConfigConstants.LDAP_CUSTOM_ATTR_WHITELIST, "*objectclass*", "entryParentId") .build(); - user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + user = new LDAPAuthenticationBackend2(settings, null).authenticate(ctx("jacksonm", "secret")); assertThat(user.getCustomAttributesMap().toString(), user.getCustomAttributesMap().size(), is(2)); @@ -921,7 +863,7 @@ public void testLdapAuthorizationNonDNRoles() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH_ENABLED, true) .build(); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), null); + User user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("nondnroles"), ctx("nondnroles", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("nondnroles")); @@ -948,7 +890,7 @@ public void testLdapAuthorizationNonDNEntry() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_ROLESEARCH, "(uniqueMember={0})") .build(); - User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), null); + User user = new LDAPAuthorizationBackend2(settings, null).addRoles(new User("jacksonm"), ctx("jacksonm", "secret")); Assert.assertNotNull(user); assertThat(user.getName(), is("jacksonm")); @@ -969,27 +911,29 @@ public void testLdapSpecial186() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), ctx("spec186", "secret")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186nn) consists of\\, special=")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -997,7 +941,7 @@ public void testLdapSpecial186() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("ROLE/(186) consists of\\, special=")); Assert.assertTrue(user.getRoles().toString().contains("ROLEx(186n) consists of\\, special=")); @@ -1017,27 +961,29 @@ public void testLdapSpecial186_2() throws Exception { .put(ConfigConstants.LDAP_AUTHZ_RESOLVE_NESTED_ROLES, true) .build(); - final LdapUser ldapUser = (LdapUser) new LDAPAuthenticationBackend(settings, null).authenticate( - new AuthCredentials("spec186", "spec186".getBytes(StandardCharsets.UTF_8)) + AuthenticationContext context = ctx("spec186", "spec186"); + User user = new LDAPAuthenticationBackend(settings, null).authenticate(context); + Assert.assertNotNull(user); + assertThat(user.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); + assertThat( + context.getContextData(LdapEntry.class).orElseThrow().getAttribute("cn").getStringValue(), + is("AA BB/CC (DD) my, company end=with=whitespace ") ); - Assert.assertNotNull(ldapUser); - assertThat(ldapUser.getName(), is("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST")); - assertThat(ldapUser.getUserEntry().getAttribute("cn").getStringValue(), is("AA BB/CC (DD) my, company end=with=whitespace ")); - User user = new LDAPAuthorizationBackend(settings, null).addRoles(ldapUser, null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(user, context); assertThat(user.getRoles().size(), is(3)); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); - user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), null); + user = new LDAPAuthorizationBackend(settings, null).addRoles(new User("spec186"), ctx("spec186", "secret")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186nn) consists of\\, special\\=chars\\ ")); user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1045,7 +991,7 @@ public void testLdapSpecial186_2() throws Exception { user = new LDAPAuthorizationBackend(settings, null).addRoles( new User("CN=AA BB\\/CC (DD) my\\, company end\\=with\\=whitespace\\ ,ou=people,o=TEST"), - null + context ); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186) consists of\\, special\\=chars\\ ")); Assert.assertTrue(user.getRoles().toString().contains("cn=ROLE/(186n) consists of\\, special\\=chars\\ ")); @@ -1060,11 +1006,10 @@ public void testOperationalAttributes() throws Exception { .put(ConfigConstants.LDAP_AUTHC_USERSEARCH, "(uid={0})") .build(); - final LdapUser user = (LdapUser) new LDAPAuthenticationBackend2(settings, null).authenticate( - new AuthCredentials("jacksonm", "secret".getBytes(StandardCharsets.UTF_8)) - ); + AuthenticationContext context = ctx("jacksonm", "secret"); + User user = new LDAPAuthenticationBackend2(settings, null).authenticate(context); Assert.assertNotNull(user); - LdapAttribute operationAttribute = user.getUserEntry().getAttribute("entryUUID"); + LdapAttribute operationAttribute = context.getContextData(LdapEntry.class).orElseThrow().getAttribute("entryUUID"); Assert.assertNotNull(operationAttribute); Assert.assertNotNull(operationAttribute.getStringValue()); Assert.assertTrue(operationAttribute.getStringValue().length() > 10); @@ -1080,4 +1025,7 @@ public static void tearDown() throws Exception { } + static AuthenticationContext ctx(String userName, String password) { + return new AuthenticationContext(new AuthCredentials(userName, password.getBytes(StandardCharsets.UTF_8))); + } } diff --git a/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java b/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java index 662d296135..9355ad7abc 100644 --- a/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java +++ b/src/test/java/org/opensearch/security/cache/DummyAuthenticationBackend.java @@ -17,8 +17,8 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ImpersonationBackend; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; public class DummyAuthenticationBackend implements AuthenticationBackend, ImpersonationBackend { @@ -34,9 +34,9 @@ public String getType() { } @Override - public User authenticate(AuthCredentials credentials) throws OpenSearchSecurityException { + public User authenticate(AuthenticationContext context) throws OpenSearchSecurityException { authCount++; - return new User(credentials.getUsername()); + return new User(context.getCredentials().getUsername()); } @Override diff --git a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java index 793f707ca2..ebd9f98733 100644 --- a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java +++ b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java @@ -15,8 +15,8 @@ import org.opensearch.OpenSearchSecurityException; import org.opensearch.common.settings.Settings; +import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.AuthorizationBackend; -import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; public class DummyAuthorizer implements AuthorizationBackend { @@ -31,7 +31,7 @@ public String getType() { } @Override - public User addRoles(User user, AuthCredentials credentials) throws OpenSearchSecurityException { + public User addRoles(User user, AuthenticationContext context) throws OpenSearchSecurityException { count++; return user.withRole("role_" + user.getName() + "_" + System.currentTimeMillis() + "_" + count); } From b30c1ac5cc74ce8092903dc6ff02ed0e067083f2 Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Fri, 16 May 2025 14:33:47 +0200 Subject: [PATCH 3/6] Polishing Signed-off-by: Nils Bandener --- .../security/OpenSearchSecurityPlugin.java | 6 +- .../security/auth/AuthorizationBackend.java | 9 +- .../security/auth/ImpersonationBackend.java | 3 + .../internal/NoOpAuthenticationBackend.java | 1 - .../org/opensearch/security/user/User.java | 102 ++++++++++++------ .../opensearch/security/user/UserFactory.java | 54 +++++++++- .../identity/SecurityTokenManagerTest.java | 5 +- 7 files changed, 137 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 084e3b2f32..84d0b7e5a6 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -1119,7 +1119,7 @@ public Collection createComponents( interClusterRequestEvaluator = ReflectionHelper.instantiateInterClusterRequestEvaluator(className, settings); } - UserFactory userFactory = new UserFactory.Caching(); + UserFactory userFactory = new UserFactory.Caching(settings); final PrivilegesInterceptor privilegesInterceptor; @@ -2146,6 +2146,10 @@ public List> getSettings() { Property.Filtered ) ); + + settings.add(UserFactory.Caching.MAX_SIZE); + settings.add(UserFactory.Caching.MAX_ENTRIES); + settings.add(UserFactory.Caching.EXPIRE_AFTER_ACCESS); } return settings; diff --git a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java index 4dfece2cf6..38a8076df6 100644 --- a/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java +++ b/src/main/java/org/opensearch/security/auth/AuthorizationBackend.java @@ -54,13 +54,12 @@ public interface AuthorizationBackend { String getType(); /** - * Populate a {@link User} with backend roles. This method will not be called for cached users. - *

- * Add them by calling either {@code user.addRole()} or {@code user.addRoles()} - *

+ * This method is called during the auth phase to add additional backend roles to a {@link User}. This method will not be called for cached users. + *

+ * Implementations must use the withRoles() method and return the newly created User object. + * * @param user The authenticated user to populate with backend roles, never null * @param context Context data specific to the request that is currently processed. - * This parameter is for future usage, currently always empty credentials are passed! * @throws OpenSearchSecurityException in case when the authorization backend cannot be reached * or the {@code credentials} are insufficient to authenticate to the authorization backend. */ diff --git a/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java b/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java index 5624d36969..9e1a11db32 100644 --- a/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java +++ b/src/main/java/org/opensearch/security/auth/ImpersonationBackend.java @@ -15,6 +15,9 @@ import org.opensearch.security.user.User; +/** + * If an authentication backend class implements this interface, the auth type can be used for impersonation. + */ public interface ImpersonationBackend { /** * The type (name) of the impersonation backend. Only for logging. diff --git a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java index 8da074cce9..ab5e65ec06 100644 --- a/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/NoOpAuthenticationBackend.java @@ -32,7 +32,6 @@ import org.opensearch.common.settings.Settings; import org.opensearch.security.auth.AuthenticationBackend; import org.opensearch.security.auth.AuthenticationContext; -import org.opensearch.security.auth.AuthenticationContext; import org.opensearch.security.auth.ImpersonationBackend; import org.opensearch.security.user.AuthCredentials; import org.opensearch.security.user.User; diff --git a/src/main/java/org/opensearch/security/user/User.java b/src/main/java/org/opensearch/security/user/User.java index 1d283d1522..7888d8ef6d 100644 --- a/src/main/java/org/opensearch/security/user/User.java +++ b/src/main/java/org/opensearch/security/user/User.java @@ -43,12 +43,16 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import org.opensearch.OpenSearchException; import org.opensearch.security.support.Base64Helper; /** - * A authenticated user and attributes associated to them (like roles, tenant, custom attributes) - *

- * Do not subclass from this class! + * An authenticated user and attributes associated to them (like roles, tenant, custom attributes). + *

+ * Objects of this class are immutable. Any method that modifies an attribute, returns a modified copy of this object. + * As the objects are immutable, all operations on the objects are inherently thread-safe. No external synchronization is required. + *

+ * Do not subclass from this class; do not add attributes that can be modified using publicly visible methods! * */ public class User implements Serializable, CustomAttributesAware { @@ -66,8 +70,12 @@ public class User implements Serializable, CustomAttributesAware { /** * Deserializes the given serialized from of a user object and returns the actual user object. - * + *

* Note: Instead of using this method, prefer to use UserFactory.Caching to benefit from already parsed user objects. + * + * @param serializedBase64 a string with a serialized form of a User object + * @return A User object. Never returns null. + * @throws OpenSearchException in case the provided string could not be processed. */ public static User fromSerializedBase64(String serializedBase64) { User user = (User) Base64Helper.deserializeObject(serializedBase64); @@ -86,26 +94,13 @@ public static User fromSerializedBase64(String serializedBase64) { private final String requestedTenant; private final ImmutableMap attributes; private final boolean isInjected; - private volatile transient String serializedBase64; + private final transient int estimatedByteSize; /** - * Create a new authenticated user - * - * @param name The username (must not be null or empty) - * @param roles Roles of which the user is a member off (maybe null) - * @param customAttributes Custom attributes associated with this (maybe null) - * @throws IllegalArgumentException if name is null or empty + * This attribute caches the serialized form of the User object. As the User object is immutable, + * this value can be re-used when it is set. */ - public User(final String name, final Collection roles, final AuthCredentials customAttributes) { - this( - name, - ImmutableSet.copyOf(roles), - ImmutableSet.of(), - null, - customAttributes != null ? ImmutableMap.copyOf(customAttributes.getAttributes()) : ImmutableMap.of(), - false - ); - } + private volatile transient String serializedBase64; /** * Create a new authenticated user without roles and attributes @@ -114,9 +109,19 @@ public User(final String name, final Collection roles, final AuthCredent * @throws IllegalArgumentException if name is null or empty */ public User(final String name) { - this(name, ImmutableSet.of(), null); + this(name, ImmutableSet.of(), ImmutableSet.of(), null, ImmutableMap.of(), false); } + /** + * Creates a new User object. This is the main constructor, prefer using this one. + * + * @param name The username; must not be null or an empty string. + * @param roles The backend roles of a user. Must not be null. For empty roles, pass ImmutableSet.of(). + * @param securityRoles The security roles of a user. Must not be null. For empty roles, pass ImmutableSet.of(). + * @param requestedTenant The requested tenant property of the user. May be null. + * @param attributes The user attributes. Must not be null. For no attributes, pass ImmutableMap.of() + * @param isInjected A flag that indicates whether the user was injected. + */ public User( String name, ImmutableSet roles, @@ -135,6 +140,7 @@ public User( this.requestedTenant = requestedTenant; this.attributes = Objects.requireNonNull(attributes); this.isInjected = isInjected; + this.estimatedByteSize = calcEstimatedByteSize(); } public final String getName() { @@ -150,9 +156,7 @@ public ImmutableSet getRoles() { } /** - * Associate this user with a backend role - * - * @param role The backend role + * Returns a new User object that additionally contains the provided backend role. */ public User withRole(String role) { return new User( @@ -166,9 +170,7 @@ public User withRole(String role) { } /** - * Associate this user with a set of backend roles - * - * @param roles The backend roles + * Returns a new User object that additionally contains the provided backend roles. */ public User withRoles(Collection roles) { if (roles == null || roles.isEmpty()) { @@ -186,9 +188,7 @@ public User withRoles(Collection roles) { } /** - * Associate this user with a set of custom attributes - * - * @param attributes custom attributes + * Returns a new User object that additionally contains the provided map of custom attributes */ public User withAttributes(Map attributes) { if (attributes == null || attributes.isEmpty()) { @@ -209,6 +209,9 @@ public final String getRequestedTenant() { return requestedTenant; } + /** + * Returns a new User object with the requestedTenant attribute set to the supplied value. + */ public User withRequestedTenant(String requestedTenant) { if (Objects.equals(requestedTenant, this.requestedTenant)) { return this; @@ -277,6 +280,9 @@ public ImmutableMap getCustomAttributesMap() { return this.attributes; } + /** + * Returns a new user object that additionally contains the given security roles. + */ public User withSecurityRoles(Collection securityRoles) { if (securityRoles == null || securityRoles.isEmpty()) { return this; @@ -315,6 +321,9 @@ public boolean isPluginUser() { return name != null && name.startsWith("plugin:"); } + /** + * Returns a String containing serialized form of this User object. Never returns null. + */ public String toSerializedBase64() { String result = this.serializedBase64; @@ -325,11 +334,42 @@ public String toSerializedBase64() { return result; } + /** + * Returns a rough estimated byte size of this object. Used for cache size control. + */ + public int estimatedByteSize() { + return this.estimatedByteSize; + } + + private int calcEstimatedByteSize() { + int size = 32; + size += estimateStringSize(this.name); + size += estimateStringSize(this.requestedTenant); + size += this.roles.stream().mapToInt(User::estimateStringSize).sum() + 32; + size += this.securityRoles.stream().mapToInt(User::estimateStringSize).sum() + 32; + size += this.attributes.entrySet() + .stream() + .mapToInt((entry) -> estimateStringSize(entry.getKey()) + estimateStringSize(entry.getValue())) + .sum() + 32; + return size; + } + + private static int estimateStringSize(String s) { + if (s != null) { + return 40 + s.length() * 2; + } else { + return 0; + } + } + void readObject(ObjectInputStream stream) throws InvalidObjectException { // This object is not supposed to directly read in order to keep compatibility with older OpenSearch versions throw new InvalidObjectException("Use org.opensearch.security.user.serialized.User"); } + /** + * Used for creating a backwards compatible object that can be used for serialization. + */ @Serial private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("name", String.class), diff --git a/src/main/java/org/opensearch/security/user/UserFactory.java b/src/main/java/org/opensearch/security/user/UserFactory.java index d3f8328a7e..17562e426a 100644 --- a/src/main/java/org/opensearch/security/user/UserFactory.java +++ b/src/main/java/org/opensearch/security/user/UserFactory.java @@ -15,6 +15,14 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.google.common.cache.Weigher; + +import org.opensearch.OpenSearchException; +import org.opensearch.common.settings.Setting; +import org.opensearch.common.settings.Settings; +import org.opensearch.common.unit.TimeValue; +import org.opensearch.core.common.unit.ByteSizeUnit; +import org.opensearch.core.common.unit.ByteSizeValue; /** * Infrastructure to create user objects. This class has two implementations: @@ -24,6 +32,13 @@ * */ public abstract class UserFactory { + /** + * Converts a serialized form of a User object to a User obect. This might use a cache. + * + * @param serializedBase64 a string with a serialized form of a User object + * @return A User object. Never returns null. + * @throws OpenSearchException in case the provided string could not be processed. + */ public abstract User fromSerializedBase64(String serializedBase64); public static class Simple extends UserFactory { @@ -35,10 +50,45 @@ public User fromSerializedBase64(String serializedBase64) { } public static class Caching extends UserFactory { + + /** + * This setting specifies the maximum estimated byte size of the cache. The size is estimated, so take it + * with a grain of salt. It shall just serve as a rough limit. The default is 10 MB. + */ + public static Setting MAX_SIZE = Setting.memorySizeSetting( + "plugins.security.transport_user_cache.max_heap_size", + new ByteSizeValue(10, ByteSizeUnit.MB), + Setting.Property.NodeScope + ); + + /** + * This setting specifies the maximum number of users inside the cache. The default is 1000 users. + */ + public static Setting MAX_ENTRIES = Setting.intSetting( + "plugins.security.transport_user_cache.max_entries", + 1000, + Setting.Property.NodeScope + ); + + /** + * This setting specifies the maximum time an entry is kept in the cache. This is solely for saving space; + * a stale cache is not possible. The default is 1 hour. + */ + public static Setting EXPIRE_AFTER_ACCESS = Setting.timeSetting( + "plugins.security.transport_user_cache.expire_after_access", + TimeValue.timeValueHours(1), + Setting.Property.NodeScope + ); + private final Cache serializedBase64ToUserCache; - public Caching() { - this.serializedBase64ToUserCache = CacheBuilder.newBuilder().expireAfterAccess(Duration.ofHours(1)).build(); + public Caching(Settings settings) { + this.serializedBase64ToUserCache = CacheBuilder.newBuilder() + .weigher((Weigher) (key, user) -> 16 + key.length() + user.estimatedByteSize()) + .maximumSize(MAX_ENTRIES.get(settings)) + .maximumWeight(MAX_SIZE.get(settings).getBytes()) + .expireAfterAccess(Duration.ofMillis(EXPIRE_AFTER_ACCESS.get(settings).millis())) + .build(); } public User fromSerializedBase64(String serializedBase64) { diff --git a/src/test/java/org/opensearch/security/identity/SecurityTokenManagerTest.java b/src/test/java/org/opensearch/security/identity/SecurityTokenManagerTest.java index d686b145b2..42ff9e04e8 100644 --- a/src/test/java/org/opensearch/security/identity/SecurityTokenManagerTest.java +++ b/src/test/java/org/opensearch/security/identity/SecurityTokenManagerTest.java @@ -12,7 +12,6 @@ package org.opensearch.security.identity; import java.io.IOException; -import java.util.List; import java.util.Set; import org.junit.After; @@ -202,7 +201,7 @@ public void issueOnBehalfOfToken_jwtGenerationFailure() throws Exception { doAnswer(invockation -> new ClusterName("cluster17")).when(cs).getClusterName(); doAnswer(invocation -> true).when(tokenManager).issueOnBehalfOfTokenAllowed(); final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User("Jon", List.of(), null)); + threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User("Jon")); when(threadPool.getThreadContext()).thenReturn(threadContext); final ConfigModel configModel = mock(ConfigModel.class); tokenManager.onConfigModelChanged(configModel); @@ -228,7 +227,7 @@ public void issueOnBehalfOfToken_success() throws Exception { doAnswer(invockation -> new ClusterName("cluster17")).when(cs).getClusterName(); doAnswer(invocation -> true).when(tokenManager).issueOnBehalfOfTokenAllowed(); final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User("Jon", List.of(), null)); + threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, new User("Jon")); when(threadPool.getThreadContext()).thenReturn(threadContext); final ConfigModel configModel = mock(ConfigModel.class); tokenManager.onConfigModelChanged(configModel); From db997634b0e50c79f3c6bc359721f4606df59bd1 Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Fri, 16 May 2025 14:55:13 +0200 Subject: [PATCH 4/6] Polishing fix Signed-off-by: Nils Bandener --- .../opensearch/security/OpenSearchSecurityPlugin.java | 1 - .../java/org/opensearch/security/user/UserFactory.java | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 84d0b7e5a6..781a80795f 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -2148,7 +2148,6 @@ public List> getSettings() { ); settings.add(UserFactory.Caching.MAX_SIZE); - settings.add(UserFactory.Caching.MAX_ENTRIES); settings.add(UserFactory.Caching.EXPIRE_AFTER_ACCESS); } diff --git a/src/main/java/org/opensearch/security/user/UserFactory.java b/src/main/java/org/opensearch/security/user/UserFactory.java index 17562e426a..a8de9ca3a9 100644 --- a/src/main/java/org/opensearch/security/user/UserFactory.java +++ b/src/main/java/org/opensearch/security/user/UserFactory.java @@ -61,15 +61,6 @@ public static class Caching extends UserFactory { Setting.Property.NodeScope ); - /** - * This setting specifies the maximum number of users inside the cache. The default is 1000 users. - */ - public static Setting MAX_ENTRIES = Setting.intSetting( - "plugins.security.transport_user_cache.max_entries", - 1000, - Setting.Property.NodeScope - ); - /** * This setting specifies the maximum time an entry is kept in the cache. This is solely for saving space; * a stale cache is not possible. The default is 1 hour. @@ -85,7 +76,6 @@ public static class Caching extends UserFactory { public Caching(Settings settings) { this.serializedBase64ToUserCache = CacheBuilder.newBuilder() .weigher((Weigher) (key, user) -> 16 + key.length() + user.estimatedByteSize()) - .maximumSize(MAX_ENTRIES.get(settings)) .maximumWeight(MAX_SIZE.get(settings).getBytes()) .expireAfterAccess(Duration.ofMillis(EXPIRE_AFTER_ACCESS.get(settings).millis())) .build(); From 07e3d565814cf9fe3baef1d1a6204705887d91b6 Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Fri, 16 May 2025 14:57:27 +0200 Subject: [PATCH 5/6] Removed replaceProperties() without PrivilegesEvaluationContext param Signed-off-by: Nils Bandener --- .../dlic/rest/api/AccountApiAction.java | 1 + .../privileges/PrivilegesEvaluator.java | 14 ++++++--- .../security/privileges/UserAttributes.java | 30 ------------------- .../security/securityconf/ConfigModel.java | 3 +- .../security/securityconf/ConfigModelV7.java | 15 ++++++---- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java index 45f97b0931..8f473ff3d2 100644 --- a/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java +++ b/src/main/java/org/opensearch/security/dlic/rest/api/AccountApiAction.java @@ -128,6 +128,7 @@ private void userAccount( final SecurityDynamicConfiguration configuration ) { final var securityRoles = securityApiDependencies.privilegesEvaluator().mapRoles(user, remoteAddress); + ok( channel, (builder, params) -> builder.startObject() diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index c29cc7ab84..8b0e28d883 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -455,7 +455,7 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) user, dcm, requestedResolved, - mapTenants(user, mappedRoles) + mapTenants(context) ); if (isDebugEnabled) { @@ -517,7 +517,7 @@ public PrivilegesEvaluatorResponse evaluate(PrivilegesEvaluationContext context) user, dcm, requestedResolved, - mapTenants(user, mappedRoles) + mapTenants(context) ); if (isDebugEnabled) { @@ -594,8 +594,14 @@ public Set mapRoles(final User user, final TransportAddress caller) { return this.configModel.mapSecurityRoles(user, caller); } - public Map mapTenants(final User user, Set roles) { - return this.configModel.mapTenants(user, roles); + public Map mapTenants(PrivilegesEvaluationContext privilegesEvaluationContext) { + return this.configModel.mapTenants(privilegesEvaluationContext); + } + + public Map mapTenants(User user, Set mappedRoles) { + return this.configModel.mapTenants( + new PrivilegesEvaluationContext(user, ImmutableSet.copyOf(mappedRoles), null, null, null, irr, resolver, clusterStateSupplier) + ); } public Set getAllConfiguredTenantNames() { diff --git a/src/main/java/org/opensearch/security/privileges/UserAttributes.java b/src/main/java/org/opensearch/security/privileges/UserAttributes.java index a1a949d96c..2f5dfeed35 100644 --- a/src/main/java/org/opensearch/security/privileges/UserAttributes.java +++ b/src/main/java/org/opensearch/security/privileges/UserAttributes.java @@ -52,26 +52,6 @@ private static String replaceSecurityRoles(final String orig, PrivilegesEvaluati return retVal; } - @Deprecated - public static String replaceProperties(String orig, User user) { - - if (user == null || orig == null) { - return orig; - } - - orig = orig.replace("${user.name}", user.getName()).replace("${user_name}", user.getName()); - orig = replaceRoles(orig, user); - orig = replaceSecurityRoles(orig, user); - for (Map.Entry entry : user.getCustomAttributesMap().entrySet()) { - if (entry == null || entry.getKey() == null || entry.getValue() == null) { - continue; - } - orig = orig.replace("${" + entry.getKey() + "}", entry.getValue()); - orig = orig.replace("${" + entry.getKey().replace('.', '_') + "}", entry.getValue()); - } - return orig; - } - private static String replaceRoles(final String orig, final User user) { String retVal = orig; if (orig.contains("${user.roles}") || orig.contains("${user_roles}")) { @@ -81,16 +61,6 @@ private static String replaceRoles(final String orig, final User user) { return retVal; } - @Deprecated - private static String replaceSecurityRoles(final String orig, final User user) { - String retVal = orig; - if (orig.contains("${user.securityRoles}") || orig.contains("${user_securityRoles}")) { - final String commaSeparatedRoles = toQuotedCommaSeparatedString(user.getSecurityRoles()); - retVal = orig.replace("${user.securityRoles}", commaSeparatedRoles).replace("${user_securityRoles}", commaSeparatedRoles); - } - return retVal; - } - private static String toQuotedCommaSeparatedString(final Set roles) { return Joiner.on(',').join(Iterables.transform(roles, s -> { return new StringBuilder(s.length() + 2).append('"').append(s).append('"').toString(); diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModel.java b/src/main/java/org/opensearch/security/securityconf/ConfigModel.java index 7429a2c776..89b0a38364 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModel.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModel.java @@ -30,11 +30,12 @@ import java.util.Set; import org.opensearch.core.common.transport.TransportAddress; +import org.opensearch.security.privileges.PrivilegesEvaluationContext; import org.opensearch.security.user.User; public abstract class ConfigModel { - public abstract Map mapTenants(User user, Set roles); + public abstract Map mapTenants(PrivilegesEvaluationContext privilegesEvaluationContext); public abstract Set mapSecurityRoles(User user, TransportAddress caller); diff --git a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java index be242e38d8..c31b062bd9 100644 --- a/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java +++ b/src/main/java/org/opensearch/security/securityconf/ConfigModelV7.java @@ -45,6 +45,7 @@ import org.opensearch.common.collect.Tuple; import org.opensearch.common.settings.Settings; import org.opensearch.core.common.transport.TransportAddress; +import org.opensearch.security.privileges.PrivilegesEvaluationContext; import org.opensearch.security.privileges.UserAttributes; import org.opensearch.security.securityconf.impl.SecurityDynamicConfiguration; import org.opensearch.security.securityconf.impl.v7.ActionGroupsV7; @@ -192,12 +193,15 @@ public Tuple>> call() throws Exception { } - public Map mapTenants(final User user, Set roles) { + public Map mapTenants(PrivilegesEvaluationContext privilegesEvaluationContext) { - if (user == null || tenantsMM == null) { + if (privilegesEvaluationContext == null || tenantsMM == null) { return Collections.emptyMap(); } + User user = privilegesEvaluationContext.getUser(); + Set roles = privilegesEvaluationContext.getMappedRoles(); + final Map result = new HashMap<>(roles.size()); result.put(user.getName(), true); @@ -210,7 +214,7 @@ public Map mapTenants(final User user, Set roles) { // replaceProperties for tenant name because // at this point e.getValue().v1() can be in this form : "${attr.[internal|jwt|proxy|ldap].*}" // let's substitute it with the eventual value of the user's attribute - final String tenant = UserAttributes.replaceProperties(e.getValue().v1(), user); + final String tenant = UserAttributes.replaceProperties(e.getValue().v1(), privilegesEvaluationContext); final boolean rw = e.getValue().v2(); if (rw || !result.containsKey(tenant)) { // RW outperforms RO @@ -353,8 +357,9 @@ private Set map(final User user, final TransportAddress caller) { } } - public Map mapTenants(User user, Set roles) { - return tenantHolder.mapTenants(user, roles); + @Override + public Map mapTenants(PrivilegesEvaluationContext privilegesEvaluationContext) { + return tenantHolder.mapTenants(privilegesEvaluationContext); } public Set mapSecurityRoles(User user, TransportAddress caller) { From 1dadf8a720d70b7e98f0aabdc8ceac280323944e Mon Sep 17 00:00:00 2001 From: Nils Bandener Date: Fri, 16 May 2025 17:12:22 +0200 Subject: [PATCH 6/6] Tests and polishing Signed-off-by: Nils Bandener --- .../security/user/UserFactoryTest.java | 65 +++++++++++++++++++ .../opensearch/security/user/UserTest.java | 59 +++++++++++++++++ .../InternalAuthenticationBackend.java | 9 +-- .../auth/ldap2/LDAPAuthorizationBackend2.java | 4 +- .../org/opensearch/security/user/User.java | 18 ++--- .../opensearch/security/user/UserFactory.java | 5 +- .../security/cache/DummyAuthorizer.java | 2 +- 7 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 src/integrationTest/java/org/opensearch/security/user/UserFactoryTest.java diff --git a/src/integrationTest/java/org/opensearch/security/user/UserFactoryTest.java b/src/integrationTest/java/org/opensearch/security/user/UserFactoryTest.java new file mode 100644 index 0000000000..facbc23906 --- /dev/null +++ b/src/integrationTest/java/org/opensearch/security/user/UserFactoryTest.java @@ -0,0 +1,65 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +package org.opensearch.security.user; + +import java.util.Arrays; +import java.util.Collection; + +import com.google.common.collect.ImmutableSet; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import org.opensearch.OpenSearchException; +import org.opensearch.common.settings.Settings; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +@RunWith(Parameterized.class) +public class UserFactoryTest { + UserFactory subject; + + @Test + public void parse_successful() { + User source = new User("test_user").withRoles(ImmutableSet.of("a", "b")); + User target = subject.fromSerializedBase64(source.toSerializedBase64()); + + assertEquals(source, target); + } + + @Test + public void parse_invalid() { + try { + User target = subject.fromSerializedBase64("invaliddata123"); + fail("Should have failed; got " + target); + } catch (Exception e) { + assertTrue( + "Got invalid stream header " + e, + e instanceof OpenSearchException && e.getMessage().contains("invalid stream header") + ); + } + } + + public UserFactoryTest(UserFactory subject, String name) { + this.subject = subject; + } + + @Parameterized.Parameters(name = "{1}") + public static Collection params() { + return Arrays.asList( + new Object[] { new UserFactory.Simple(), "Simple" }, + new Object[] { new UserFactory.Caching(Settings.EMPTY), "Caching" } + ); + } +} diff --git a/src/integrationTest/java/org/opensearch/security/user/UserTest.java b/src/integrationTest/java/org/opensearch/security/user/UserTest.java index 8a8c104e05..7d8b2fa152 100644 --- a/src/integrationTest/java/org/opensearch/security/user/UserTest.java +++ b/src/integrationTest/java/org/opensearch/security/user/UserTest.java @@ -11,13 +11,16 @@ package org.opensearch.security.user; import java.util.Arrays; +import java.util.Map; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import org.junit.Test; import org.opensearch.security.support.Base64Helper; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; public class UserTest { @Test @@ -76,4 +79,60 @@ public void deserializationLdapUserFrom2_19() { user ); } + + @Test + public void withRoles() { + User original = new User("test_user").withRoles("a"); + User modified = original.withRoles("b"); + + assertEquals(ImmutableSet.of("a"), original.getRoles()); + assertEquals(ImmutableSet.of("a", "b"), modified.getRoles()); + } + + @Test + public void withRoles_unmodified() { + User original = new User("test_user").withRoles("a"); + User unmodified = original.withRoles(ImmutableSet.of()); + + assertSame(original, unmodified); + } + + @Test + public void withAttributes() { + User original = new User("test_user").withAttributes(Map.of("a", "1")); + User modified = original.withAttributes(Map.of("b", "2")); + + assertEquals(ImmutableMap.of("a", "1"), original.getCustomAttributesMap()); + assertEquals(ImmutableMap.of("a", "1", "b", "2"), modified.getCustomAttributesMap()); + } + + @Test + public void withAttributes_unmodified() { + User original = new User("test_user").withAttributes(Map.of("a", "1")); + User unmodified = original.withAttributes(Map.of()); + + assertSame(original, unmodified); + } + + @Test + public void withRequestedTenant() { + User original = new User("test_user").withRequestedTenant("a"); + User modified = original.withRequestedTenant("b"); + + assertEquals("a", original.getRequestedTenant()); + assertEquals("b", modified.getRequestedTenant()); + } + + @Test + public void withRequestedTenant_unmodified() { + User original = new User("test_user").withRequestedTenant("a"); + User unmodified = original.withRequestedTenant("a"); + + assertSame(original, unmodified); + } + + @Test(expected = IllegalArgumentException.class) + public void illegalName() { + new User(""); + } } diff --git a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java index c3e74a4621..6ccead820e 100644 --- a/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java +++ b/src/main/java/org/opensearch/security/auth/internal/InternalAuthenticationBackend.java @@ -30,7 +30,6 @@ import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.util.Map; import java.util.Map.Entry; import java.util.Optional; @@ -69,13 +68,11 @@ public Optional impersonate(User user) { if (exists) { // FIX https://github.com/opendistro-for-elasticsearch/security/pull/23 // Credits to @turettn - final Map customAttributes = internalUsersModel.getAttributes(user.getName()); + ImmutableMap customAttributes = internalUsersModel.getAttributes(user.getName()); ImmutableMap.Builder attributeMap = ImmutableMap.builder(); - if (customAttributes != null) { - for (Entry attributeEntry : customAttributes.entrySet()) { - attributeMap.put("attr.internal." + attributeEntry.getKey(), attributeEntry.getValue()); - } + for (Entry attributeEntry : customAttributes.entrySet()) { + attributeMap.put("attr.internal." + attributeEntry.getKey(), attributeEntry.getValue()); } return Optional.of( diff --git a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java index f9495fff42..419b2aa352 100755 --- a/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java +++ b/src/main/java/org/opensearch/security/auth/ldap2/LDAPAuthorizationBackend2.java @@ -186,9 +186,7 @@ private User addRoles0(final User user, AuthenticationContext context) throws Op } if (skipUsersMatcher.test(authenticatedUser)) { - if (isDebugEnabled) { - log.debug("Skipped search roles of user {}/{}", authenticatedUser, originalUserName); - } + log.debug("Skipped search roles of user {}/{}", authenticatedUser, originalUserName); return user; } diff --git a/src/main/java/org/opensearch/security/user/User.java b/src/main/java/org/opensearch/security/user/User.java index 7888d8ef6d..4605efe674 100644 --- a/src/main/java/org/opensearch/security/user/User.java +++ b/src/main/java/org/opensearch/security/user/User.java @@ -33,6 +33,7 @@ import java.io.ObjectStreamField; import java.io.Serial; import java.io.Serializable; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -57,14 +58,14 @@ */ public class User implements Serializable, CustomAttributesAware { - public static final User ANONYMOUS = new User("opendistro_security_anonymous").withRole("opendistro_security_anonymous_backendrole"); + public static final User ANONYMOUS = new User("opendistro_security_anonymous").withRoles("opendistro_security_anonymous_backendrole"); // This is a default user that is injected into a transport request when a user info is not present and passive_intertransport_auth is // enabled. // This is to be used in scenarios where some of the nodes do not have security enabled, and therefore do not pass any user information // in threadcontext, yet we need the communication to not break between the nodes. // Attach the required permissions to either the user or the backend role. - public static final User DEFAULT_TRANSPORT_USER = new User("opendistro_security_default_transport_user").withRole( + public static final User DEFAULT_TRANSPORT_USER = new User("opendistro_security_default_transport_user").withRoles( "opendistro_security_default_transport_backendrole" ); @@ -156,17 +157,10 @@ public ImmutableSet getRoles() { } /** - * Returns a new User object that additionally contains the provided backend role. + * Returns a new User object that additionally contains the provided backend roles. */ - public User withRole(String role) { - return new User( - this.name, - new ImmutableSet.Builder().addAll(this.roles).add(role).build(), - this.securityRoles, - this.requestedTenant, - this.attributes, - this.isInjected - ); + public User withRoles(String... roles) { + return withRoles(Arrays.asList(roles)); } /** diff --git a/src/main/java/org/opensearch/security/user/UserFactory.java b/src/main/java/org/opensearch/security/user/UserFactory.java index a8de9ca3a9..698d8aeeb1 100644 --- a/src/main/java/org/opensearch/security/user/UserFactory.java +++ b/src/main/java/org/opensearch/security/user/UserFactory.java @@ -16,6 +16,7 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.Weigher; +import com.google.common.util.concurrent.UncheckedExecutionException; import org.opensearch.OpenSearchException; import org.opensearch.common.settings.Setting; @@ -84,11 +85,11 @@ public Caching(Settings settings) { public User fromSerializedBase64(String serializedBase64) { try { return serializedBase64ToUserCache.get(serializedBase64, () -> User.fromSerializedBase64(serializedBase64)); - } catch (ExecutionException e) { + } catch (ExecutionException | UncheckedExecutionException e) { if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); } else { - throw new RuntimeException(e); + throw new RuntimeException(e.getCause()); } } } diff --git a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java index ebd9f98733..4164538289 100644 --- a/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java +++ b/src/test/java/org/opensearch/security/cache/DummyAuthorizer.java @@ -33,7 +33,7 @@ public String getType() { @Override public User addRoles(User user, AuthenticationContext context) throws OpenSearchSecurityException { count++; - return user.withRole("role_" + user.getName() + "_" + System.currentTimeMillis() + "_" + count); + return user.withRoles("role_" + user.getName() + "_" + System.currentTimeMillis() + "_" + count); } public static long getCount() {