diff --git a/core/src/main/java/org/springframework/ldap/core/DefaultLdapClient.java b/core/src/main/java/org/springframework/ldap/core/DefaultLdapClient.java index 1f8cd0b7e..ee5fea492 100644 --- a/core/src/main/java/org/springframework/ldap/core/DefaultLdapClient.java +++ b/core/src/main/java/org/springframework/ldap/core/DefaultLdapClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,6 +70,8 @@ class DefaultLdapClient implements LdapClient { private static final boolean RETURN_OBJ_FLAG = true; + private final Builder builder; + private final ContextSource contextSource; private final Supplier searchControlsSupplier; @@ -80,9 +82,11 @@ class DefaultLdapClient implements LdapClient { private boolean ignoreSizeLimitExceededException = true; - DefaultLdapClient(ContextSource contextSource, Supplier searchControlsSupplier) { + DefaultLdapClient(ContextSource contextSource, Supplier searchControlsSupplier, + LdapClient.Builder builder) { this.contextSource = contextSource; this.searchControlsSupplier = searchControlsSupplier; + this.builder = builder; } @Override @@ -153,7 +157,7 @@ public UnbindSpec unbind(Name name) { */ @Override public Builder mutate() { - return new DefaultLdapClientBuilder(this.contextSource, this.searchControlsSupplier); + return this.builder; } /** diff --git a/core/src/main/java/org/springframework/ldap/core/DefaultLdapClientBuilder.java b/core/src/main/java/org/springframework/ldap/core/DefaultLdapClientBuilder.java index cc1b83cb5..6146cd488 100644 --- a/core/src/main/java/org/springframework/ldap/core/DefaultLdapClientBuilder.java +++ b/core/src/main/java/org/springframework/ldap/core/DefaultLdapClientBuilder.java @@ -47,6 +47,20 @@ class DefaultLdapClientBuilder implements LdapClient.Builder { this.searchControlsSupplier = searchControlsSupplier; } + DefaultLdapClientBuilder(LdapTemplate ldap) { + this.contextSource = ldap.getContextSource(); + this.searchControlsSupplier = () -> { + SearchControls controls = new SearchControls(); + controls.setSearchScope(ldap.getDefaultSearchScope()); + controls.setCountLimit(ldap.getDefaultCountLimit()); + controls.setTimeLimit(ldap.getDefaultTimeLimit()); + return controls; + }; + this.ignoreNameNotFoundException = ldap.isIgnoreNameNotFoundException(); + this.ignoreSizeLimitExceededException = ldap.isIgnoreSizeLimitExceededException(); + this.ignorePartialResultException = ldap.isIgnorePartialResultException(); + } + @Override public DefaultLdapClientBuilder contextSource(ContextSource contextSource) { this.contextSource = contextSource; @@ -99,7 +113,7 @@ public DefaultLdapClientBuilder clone() { @Override public LdapClient build() { - DefaultLdapClient client = new DefaultLdapClient(this.contextSource, this.searchControlsSupplier); + DefaultLdapClient client = new DefaultLdapClient(this.contextSource, this.searchControlsSupplier, this); client.setIgnorePartialResultException(this.ignorePartialResultException); client.setIgnoreSizeLimitExceededException(this.ignoreSizeLimitExceededException); client.setIgnoreNameNotFoundException(this.ignoreNameNotFoundException); diff --git a/core/src/main/java/org/springframework/ldap/core/LdapClient.java b/core/src/main/java/org/springframework/ldap/core/LdapClient.java index c95af76bc..3092dceac 100644 --- a/core/src/main/java/org/springframework/ldap/core/LdapClient.java +++ b/core/src/main/java/org/springframework/ldap/core/LdapClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2023 the original author or authors. + * Copyright 2005-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -167,6 +167,16 @@ static LdapClient create(ContextSource contextSource) { return new DefaultLdapClientBuilder().contextSource(contextSource).build(); } + /** + * Create an instance of {@link LdapClient} + * @param ldap the {@link LdapTemplate} to base this client off of + * @since 3.3 + * @see #builder() + */ + static LdapClient create(LdapTemplate ldap) { + return new DefaultLdapClientBuilder(ldap).build(); + } + /** * Obtain a {@code LdapClient} builder. */ diff --git a/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java b/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java index 3cacd5c8c..5328ec0f5 100644 --- a/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java +++ b/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java @@ -166,6 +166,10 @@ public void setIgnoreNameNotFoundException(boolean ignore) { this.ignoreNameNotFoundException = ignore; } + boolean isIgnoreNameNotFoundException() { + return this.ignoreNameNotFoundException; + } + /** * Specify whether PartialResultException should be ignored in searches. * AD servers typically have a problem with referrals. Normally a referral should be @@ -182,6 +186,10 @@ public void setIgnorePartialResultException(boolean ignore) { this.ignorePartialResultException = ignore; } + boolean isIgnorePartialResultException() { + return this.ignorePartialResultException; + } + /** * Specify whether SizeLimitExceededException should be ignored in * searches. This is typically what you want if you specify count limit in your search @@ -194,6 +202,10 @@ public void setIgnoreSizeLimitExceededException(boolean ignore) { this.ignoreSizeLimitExceededException = ignore; } + boolean isIgnoreSizeLimitExceededException() { + return this.ignoreSizeLimitExceededException; + } + /** * Set the default scope to be used in searches if not explicitly specified. Default * is {@link javax.naming.directory.SearchControls#SUBTREE_SCOPE}. @@ -206,6 +218,10 @@ public void setDefaultSearchScope(int defaultSearchScope) { this.defaultSearchScope = defaultSearchScope; } + int getDefaultSearchScope() { + return this.defaultSearchScope; + } + /** * Set the default time limit be used in searches if not explicitly specified. Default * is 0, indicating no time limit. @@ -216,6 +232,10 @@ public void setDefaultTimeLimit(int defaultTimeLimit) { this.defaultTimeLimit = defaultTimeLimit; } + int getDefaultTimeLimit() { + return this.defaultTimeLimit; + } + /** * Set the default count limit be used in searches if not explicitly specified. * Default is 0, indicating no count limit. @@ -226,6 +246,10 @@ public void setDefaultCountLimit(int defaultCountLimit) { this.defaultCountLimit = defaultCountLimit; } + int getDefaultCountLimit() { + return this.defaultCountLimit; + } + /** * {@inheritDoc} */ diff --git a/core/src/test/java/org/springframework/ldap/core/DefaultLdapClientTests.java b/core/src/test/java/org/springframework/ldap/core/DefaultLdapClientTests.java index 8e572b2ee..82d8b52bd 100644 --- a/core/src/test/java/org/springframework/ldap/core/DefaultLdapClientTests.java +++ b/core/src/test/java/org/springframework/ldap/core/DefaultLdapClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2023 the original author or authors. + * Copyright 2005-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -645,6 +645,21 @@ public void testAuthenticateWithFailedAuthenticationShouldFail() throws Exceptio verify(this.dirContextMock).close(); } + @Test + public void createWhenLdapTemplateThenUses() { + LdapTemplate ldap = mock(LdapTemplate.class); + given(ldap.getContextSource()).willReturn(this.contextSourceMock); + given(this.contextSourceMock.getReadOnlyContext()).willReturn(this.dirContextMock); + LdapClient.create(ldap).search().name("dc=name").toEntryStream(); + verify(ldap).getContextSource(); + verify(ldap).isIgnoreNameNotFoundException(); + verify(ldap).isIgnorePartialResultException(); + verify(ldap).isIgnoreSizeLimitExceededException(); + verify(ldap).getDefaultCountLimit(); + verify(ldap).getDefaultSearchScope(); + verify(ldap).getDefaultTimeLimit(); + } + private void noSearchResults(SearchControls controls) throws Exception { given(this.dirContextMock.search(eq(this.nameMock), eq("(ou=somevalue)"), argThat(new SearchControlsMatcher(controls)))) diff --git a/modules/ROOT/pages/introduction.adoc b/modules/ROOT/pages/introduction.adoc index 1c483150d..3ec785080 100644 --- a/modules/ROOT/pages/introduction.adoc +++ b/modules/ROOT/pages/introduction.adoc @@ -214,6 +214,8 @@ The following list briefly describes the most important changes in Spring LDAP 2 * The https://github.com/spring-projects/spring-ldap/tree/main/samples[samples] have been polished and updated to make use of the features in 2.0. Quite a bit of effort has been put into providing a useful example of an https://github.com/spring-projects/spring-ldap/tree/main/samples/user-admin[LDAP user management application]. +* Added `LdapClient.create(LdapTemplate)` to simplify constructing an `LdapClient` from an `LdapTemplate` + [[spring-ldap-packaging-overview]] == Packaging Overview