mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-23 20:42:14 +00:00
Remove ApacheDS Support
Closes gh-13852
This commit is contained in:
parent
42e24aa53c
commit
6ddb964c61
@ -78,12 +78,6 @@ dependencies {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
exclude group: 'xml-apis', module: 'xml-apis'
|
||||
}
|
||||
testImplementation "org.apache.directory.server:apacheds-core"
|
||||
testImplementation "org.apache.directory.server:apacheds-core-entry"
|
||||
testImplementation "org.apache.directory.server:apacheds-protocol-shared"
|
||||
testImplementation "org.apache.directory.server:apacheds-protocol-ldap"
|
||||
testImplementation "org.apache.directory.server:apacheds-server-jndi"
|
||||
testImplementation 'org.apache.directory.shared:shared-ldap'
|
||||
testImplementation "com.unboundid:unboundid-ldapsdk"
|
||||
testImplementation 'jakarta.persistence:jakarta.persistence-api'
|
||||
testImplementation "org.hibernate.orm:hibernate-core"
|
||||
|
@ -44,7 +44,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
@ -326,11 +326,11 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
|
||||
abstract static class BaseLdapServerConfig extends BaseLdapProviderConfig {
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
|
||||
UnboundIdContainer ldapServer() throws Exception {
|
||||
UnboundIdContainer unboundIdContainer = new UnboundIdContainer("dc=springframework,dc=org",
|
||||
"classpath:/test-server.ldif");
|
||||
apacheDSContainer.setPort(getPort());
|
||||
return apacheDSContainer;
|
||||
unboundIdContainer.setPort(getPort());
|
||||
return unboundIdContainer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMap
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
|
||||
@ -226,18 +226,18 @@ public class LdapBindAuthenticationManagerFactoryITests {
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
UnboundIdContainer ldapServer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||
int port = container.getPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ import org.springframework.security.config.test.SpringTestContextExtension;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
|
||||
@ -93,18 +93,18 @@ public class LdapPasswordComparisonAuthenticationManagerFactoryITests {
|
||||
@EnableWebSecurity
|
||||
abstract static class BaseLdapServerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapServer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
UnboundIdContainer ldapServer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
BaseLdapPathContextSource contextSource(ApacheDSContainer container) {
|
||||
int port = container.getLocalPort();
|
||||
BaseLdapPathContextSource contextSource(UnboundIdContainer container) {
|
||||
int port = container.getPort();
|
||||
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("otherben", "otherbenspassword"));
|
||||
UserDetails ben = (UserDetails) auth.getPrincipal();
|
||||
assertThat(ben.getAuthorities()).hasSize(3);
|
||||
}
|
||||
@ -127,6 +127,27 @@ public class LdapProviderBeanDefinitionParserTests {
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsShaPasswordEncoder() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext("""
|
||||
<ldap-server ldif='classpath:test-server.ldif' port='0'/>
|
||||
<authentication-manager>
|
||||
<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>
|
||||
<password-compare>
|
||||
<password-encoder ref='pe' />
|
||||
</password-compare>
|
||||
</ldap-authentication-provider>
|
||||
</authentication-manager>
|
||||
<b:bean id='pe' class='org.springframework.security.crypto.password.LdapShaPasswordEncoder' />
|
||||
""");
|
||||
AuthenticationManager authenticationManager = this.appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
|
||||
AuthenticationManager.class);
|
||||
Authentication auth = authenticationManager
|
||||
.authenticate(UsernamePasswordAuthenticationToken.unauthenticated("ben", "benspassword"));
|
||||
|
||||
assertThat(auth).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext(
|
||||
|
@ -26,7 +26,7 @@ import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -92,9 +92,9 @@ public class LdapServerBeanDefinitionParserTests {
|
||||
@Test
|
||||
public void defaultLdifFileIsSuccessful() {
|
||||
this.appCtx = new InMemoryXmlApplicationContext("<ldap-server/>");
|
||||
ApacheDSContainer dsContainer = this.appCtx.getBean(ApacheDSContainer.class);
|
||||
UnboundIdContainer dsContainer = this.appCtx.getBean(UnboundIdContainer.class);
|
||||
|
||||
assertThat(ReflectionTestUtils.getField(dsContainer, "ldifResources")).isEqualTo("classpath*:*.ldif");
|
||||
assertThat(ReflectionTestUtils.getField(dsContainer, "ldif")).isEqualTo("classpath*:*.ldif");
|
||||
}
|
||||
|
||||
private int getDefaultPort() throws IOException {
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
||||
|
||||
<logger name="org.apache.directory" level="ERROR"/>
|
||||
<logger name="JdbmTable" level="INFO"/>
|
||||
<logger name="JdbmIndex" level="INFO"/>
|
||||
<logger name="org.apache.mina" level="WARN"/>
|
||||
|
@ -54,8 +54,6 @@ public abstract class BeanIds {
|
||||
|
||||
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
|
||||
|
||||
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
|
||||
|
||||
public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer";
|
||||
|
||||
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
|
||||
|
@ -37,7 +37,6 @@ import org.springframework.security.ldap.authentication.LdapAuthenticator;
|
||||
import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.security.ldap.search.LdapUserSearch;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
|
||||
import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
|
||||
@ -60,12 +59,8 @@ import org.springframework.util.ClassUtils;
|
||||
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
|
||||
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
|
||||
|
||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
||||
|
||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||
|
||||
private static final boolean apacheDsPresent;
|
||||
|
||||
private static final boolean unboundIdPresent;
|
||||
|
||||
private String groupRoleAttribute = "cn";
|
||||
@ -100,7 +95,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = LdapAuthenticationProviderConfigurer.class.getClassLoader();
|
||||
apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
|
||||
unboundIdPresent = ClassUtils.isPresent(UNBOUNDID_CLASSNAME, classLoader);
|
||||
}
|
||||
|
||||
@ -467,8 +461,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
*/
|
||||
public final class ContextSourceBuilder {
|
||||
|
||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
||||
|
||||
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||
|
||||
private static final int DEFAULT_PORT = 33389;
|
||||
@ -584,14 +576,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
private void startEmbeddedLdapServer() throws Exception {
|
||||
if (apacheDsPresent) {
|
||||
ApacheDSContainer apacheDsContainer = new ApacheDSContainer(this.root, this.ldif);
|
||||
apacheDsContainer.setPort(getPort());
|
||||
postProcess(apacheDsContainer);
|
||||
this.port = apacheDsContainer.getLocalPort();
|
||||
}
|
||||
else if (unboundIdPresent) {
|
||||
private void startEmbeddedLdapServer() {
|
||||
if (unboundIdPresent) {
|
||||
UnboundIdContainer unboundIdContainer = new UnboundIdContainer(this.root, this.ldif);
|
||||
unboundIdContainer.setPort(getPort());
|
||||
postProcess(unboundIdContainer);
|
||||
|
@ -32,7 +32,6 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -47,7 +46,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
private static final String CONTEXT_SOURCE_CLASS = "org.springframework.security.ldap.DefaultSpringSecurityContextSource";
|
||||
|
||||
/**
|
||||
* Defines the Url of the ldap server to use. If not specified, an embedded apache DS
|
||||
* Defines the Url of the ldap server to use. If not specified, an embedded UnboundID
|
||||
* instance will be created
|
||||
*/
|
||||
private static final String ATT_URL = "url";
|
||||
@ -78,22 +77,15 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private static final int DEFAULT_PORT = 33389;
|
||||
|
||||
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
|
||||
|
||||
private static final String UNBOUNID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
|
||||
|
||||
private static final String APACHEDS_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.ApacheDSContainer";
|
||||
|
||||
private static final String UNBOUNDID_CONTAINER_CLASSNAME = "org.springframework.security.ldap.server.UnboundIdContainer";
|
||||
|
||||
private static final boolean unboundIdPresent;
|
||||
|
||||
private static final boolean apacheDsPresent;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = LdapServerBeanDefinitionParser.class.getClassLoader();
|
||||
unboundIdPresent = ClassUtils.isPresent(UNBOUNID_CLASSNAME, classLoader);
|
||||
apacheDsPresent = ClassUtils.isPresent(APACHEDS_CLASSNAME, classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -128,10 +120,9 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
/**
|
||||
* Will be called if no url attribute is supplied.
|
||||
*
|
||||
* Registers beans to create an embedded apache directory server.
|
||||
* Registers beans to create an embedded UnboundID Server.
|
||||
* @return the BeanDefinition for the ContextSource for the embedded server.
|
||||
*
|
||||
* @see ApacheDSContainer
|
||||
* @see UnboundIdContainer
|
||||
*/
|
||||
private RootBeanDefinition createEmbeddedServer(Element element, ParserContext parserContext) {
|
||||
@ -162,8 +153,7 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
ldapContainer.getConstructorArgumentValues().addGenericArgumentValue(ldifs);
|
||||
ldapContainer.getPropertyValues().addPropertyValue("port", getPort(element));
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_APACHE_DS)
|
||||
|| parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.EMBEDDED_UNBOUNDID)) {
|
||||
parserContext.getReaderContext()
|
||||
.error("Only one embedded server bean is allowed per application context", element);
|
||||
}
|
||||
@ -175,9 +165,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private RootBeanDefinition getRootBeanDefinition(String mode) {
|
||||
if (isApacheDsEnabled(mode)) {
|
||||
return new RootBeanDefinition(APACHEDS_CONTAINER_CLASSNAME, null, null);
|
||||
}
|
||||
if (isUnboundidEnabled(mode)) {
|
||||
return new RootBeanDefinition(UNBOUNDID_CONTAINER_CLASSNAME, null, null);
|
||||
}
|
||||
@ -185,19 +172,12 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private String resolveBeanId(String mode) {
|
||||
if (isApacheDsEnabled(mode)) {
|
||||
return BeanIds.EMBEDDED_APACHE_DS;
|
||||
}
|
||||
if (isUnboundidEnabled(mode)) {
|
||||
return BeanIds.EMBEDDED_UNBOUNDID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isApacheDsEnabled(String mode) {
|
||||
return "apacheds".equals(mode) || apacheDsPresent;
|
||||
}
|
||||
|
||||
private boolean isUnboundidEnabled(String mode) {
|
||||
return "unboundid".equals(mode) || unboundIdPresent;
|
||||
}
|
||||
@ -233,10 +213,6 @@ public class LdapServerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private int getPort() {
|
||||
if (apacheDsPresent) {
|
||||
ApacheDSContainer apacheDSContainer = this.applicationContext.getBean(ApacheDSContainer.class);
|
||||
return apacheDSContainer.getLocalPort();
|
||||
}
|
||||
if (unboundIdPresent) {
|
||||
UnboundIdContainer unboundIdContainer = this.applicationContext.getBean(UnboundIdContainer.class);
|
||||
return unboundIdContainer.getPort();
|
||||
|
@ -84,8 +84,8 @@ ldap-server.attlist &=
|
||||
## Optional root suffix for the embedded LDAP server. Default is "dc=springframework,dc=org"
|
||||
attribute root { xsd:string }?
|
||||
ldap-server.attlist &=
|
||||
## Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and 'unboundid'. By default, it will depends if the library is available in the classpath.
|
||||
attribute mode { "apacheds" | "unboundid" }?
|
||||
## Explicitly specifies which embedded ldap server should use. The only supported value is 'unboundid'. By default, it will depends if the library is available in the classpath.
|
||||
attribute mode { "unboundid" }?
|
||||
|
||||
ldap-server-ref-attribute =
|
||||
## The optional server to use. If omitted, and a default LDAP server is registered (using <ldap-server> with no Id), that server will be used.
|
||||
|
@ -224,13 +224,12 @@
|
||||
</xs:attribute>
|
||||
<xs:attribute name="mode">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Explicitly specifies which embedded ldap server should use. Values are 'apacheds' and
|
||||
<xs:documentation>Explicitly specifies which embedded ldap server should use. The only supported value is
|
||||
'unboundid'. By default, it will depends if the library is available in the classpath.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="apacheds"/>
|
||||
<xs:enumeration value="unboundid"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
@ -21,7 +21,6 @@ import okhttp3.mockwebserver.Dispatcher;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import okhttp3.mockwebserver.RecordedRequest;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
@ -39,6 +38,7 @@ import org.springframework.security.oauth2.server.resource.web.reactive.function
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@ -197,7 +197,7 @@ public class SecurityReactorContextConfigurationResourceServerTests {
|
||||
public MockResponse dispatch(RecordedRequest request) {
|
||||
MockResponse response = new MockResponse().setResponseCode(200);
|
||||
String header = request.getHeader("Authorization");
|
||||
if (StringUtils.isBlank(header)) {
|
||||
if (!StringUtils.hasText(header)) {
|
||||
return response;
|
||||
}
|
||||
return response.setBody(header);
|
||||
|
@ -30,12 +30,12 @@ import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.security.config.http.SecurityFiltersAssertions;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@ -86,7 +86,7 @@ public class XsdDocumentedTests {
|
||||
.flatMap(XmlNode::children)
|
||||
.flatMap(XmlNode::children)
|
||||
.map((node) -> node.attribute("value"))
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.toList());
|
||||
// @formatter:on
|
||||
SecurityFiltersAssertions.assertEquals(nodes);
|
||||
@ -129,7 +129,7 @@ public class XsdDocumentedTests {
|
||||
.flatMap(XmlNode::children)
|
||||
.flatMap(XmlNode::children)
|
||||
.map((node) -> node.attribute("value"))
|
||||
.filter(StringUtils::isNotEmpty)
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.toList());
|
||||
// @formatter:on
|
||||
assertThat(nodes).isEqualTo(expected);
|
||||
|
@ -7,8 +7,6 @@
|
||||
|
||||
<logger name="org.springframework.security" level="${sec.log.level:-WARN}"/>
|
||||
|
||||
<logger name="org.apache.directory" level="ERROR"/>
|
||||
|
||||
<root level="${root.level:-WARN}">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
@ -49,12 +49,6 @@ dependencies {
|
||||
api libs.ldapsdk
|
||||
api libs.net.sourceforge.htmlunit
|
||||
api libs.org.htmlunit.htmlunit
|
||||
api libs.org.apache.directory.server.apacheds.entry
|
||||
api libs.org.apache.directory.server.apacheds.core
|
||||
api libs.org.apache.directory.server.apacheds.protocol.ldap
|
||||
api libs.org.apache.directory.server.apacheds.protocol.shared
|
||||
api libs.org.apache.directory.server.apacheds.server.jndi
|
||||
api libs.org.apache.directory.shared.shared.ldap
|
||||
api libs.org.apache.httpcomponents.httpclient
|
||||
api libs.org.aspectj.aspectjrt
|
||||
api libs.org.aspectj.aspectjweaver
|
||||
|
@ -166,13 +166,9 @@ The top-level package is `org.springframework.security.ldap`.
|
||||
|
|
||||
| Data exception classes are required.
|
||||
|
||||
| apache-ds
|
||||
| 1.5.5
|
||||
| Required if you are using an embedded LDAP server (optional). If you use `apache-ds`, the `apacheds-core`, `apacheds-core-entry`, `apacheds-protocol-shared`, `apacheds-protocol-ldap` and `apacheds-server-jndi` modules are required.
|
||||
|
||||
| shared-ldap
|
||||
| 0.9.15
|
||||
| Required if you are using an embedded LDAP server (optional).
|
||||
| com.unboundid:unboundid-ldapsdk
|
||||
|
|
||||
| Required if using an embedded LDAP server
|
||||
|
||||
| ldapsdk
|
||||
| 4.1
|
||||
|
@ -363,7 +363,7 @@ This section addresses common Spring Security architecture questions:
|
||||
. <<appendix-faq-namespace-to-bean-mapping>>
|
||||
. <<appendix-faq-role-prefix>>
|
||||
. <<appendix-faq-what-dependencies>>
|
||||
. <<appendix-faq-apacheds-deps>>
|
||||
. <<appendix-faq-unboundid-deps>>
|
||||
. <<appendix-faq-what-is-userdetailservice>>
|
||||
|
||||
|
||||
@ -412,30 +412,39 @@ The reference manual also includes <<appendix-namespace,an appendix>> that lists
|
||||
If you build your project with Maven, adding the appropriate Spring Security modules as dependencies to your `pom.xml` file automatically pulls in the core jars that the framework requires.
|
||||
Any that are marked as "`optional`" in the Spring Security `pom.xml` files have to be added to your own `pom.xml` file if you need them.
|
||||
|
||||
[[appendix-faq-unboundid-deps]]
|
||||
=== What dependences are needed to run an embedded UnboundID LDAP server?
|
||||
|
||||
You need to add the following dependency to your project:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,maven,role="primary"]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>com.unboundid</groupId>
|
||||
<artifactId>unboundid-ldapsdk</artifactId>
|
||||
<version>7.0.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,gradle,role="secondary"]
|
||||
----
|
||||
implementation 'com.unboundid:unboundid-ldapsdk:7.0.1'
|
||||
----
|
||||
======
|
||||
|
||||
|
||||
[[appendix-faq-apacheds-deps]]
|
||||
=== What dependencies are needed to run an embedded ApacheDS LDAP server?
|
||||
|
||||
If you use Maven, you need to add the following to your `pom.xml` file dependencies:
|
||||
|
||||
[source]
|
||||
----
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-jndi</artifactId>
|
||||
<version>1.5.5</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
----
|
||||
|
||||
The other required jars should be pulled in transitively.
|
||||
Spring Security 7 removes support for Apache DS.
|
||||
Please use <<appendix-faq-unboundid-deps,UnboundID>> instead.
|
||||
|
||||
[[appendix-faq-what-is-userdetailservice]]
|
||||
=== What is a UserDetailsService and do I need one?
|
||||
|
@ -24,7 +24,7 @@ This is actually the bean `id` of the `ContextSource` instance, if you want to u
|
||||
|
||||
[[nsa-ldap-server-mode]]
|
||||
* **mode**
|
||||
Explicitly specifies which embedded ldap server should use. Values are `apacheds` and `unboundid`. By default, it will depends if the library is available in the classpath.
|
||||
Explicitly specifies which embedded ldap server should use. The only supported value is `unboundid`. By default, it will depends if the library is available in the classpath.
|
||||
|
||||
[[nsa-ldap-server-id]]
|
||||
* **id**
|
||||
|
@ -223,82 +223,8 @@ fun ldapContainer(): UnboundIdContainer {
|
||||
[[servlet-authentication-ldap-apacheds]]
|
||||
=== Embedded ApacheDS Server
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Spring Security uses ApacheDS 1.x, which is no longer maintained.
|
||||
Unfortunately, ApacheDS 2.x has only released milestone versions with no stable release.
|
||||
Once a stable release of ApacheDS 2.x is available, we will consider updating.
|
||||
====
|
||||
|
||||
If you wish to use https://directory.apache.org/apacheds/[Apache DS], specify the following dependencies:
|
||||
|
||||
.ApacheDS Dependencies
|
||||
[tabs]
|
||||
======
|
||||
Maven::
|
||||
+
|
||||
[source,xml,role="primary",subs="+attributes"]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-core</artifactId>
|
||||
<version>{apacheds-core-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-server-jndi</artifactId>
|
||||
<version>{apacheds-core-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
Gradle::
|
||||
+
|
||||
[source,groovy,role="secondary",subs="+attributes"]
|
||||
----
|
||||
depenendencies {
|
||||
runtimeOnly "org.apache.directory.server:apacheds-core:{apacheds-core-version}"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-server-jndi:{apacheds-core-version}"
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
You can then configure the Embedded LDAP Server:
|
||||
|
||||
.Embedded LDAP Server Configuration
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
ApacheDSContainer ldapContainer() {
|
||||
return new ApacheDSContainer("dc=springframework,dc=org",
|
||||
"classpath:users.ldif");
|
||||
}
|
||||
----
|
||||
|
||||
XML::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<b:bean class="org.springframework.security.ldap.server.ApacheDSContainer"
|
||||
c:defaultPartitionSuffix="dc=springframework,dc=org"
|
||||
c:ldif="classpath:users.ldif"/>
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun ldapContainer(): ApacheDSContainer {
|
||||
return ApacheDSContainer("dc=springframework,dc=org", "classpath:users.ldif")
|
||||
}
|
||||
----
|
||||
======
|
||||
Spring Security 7 removes support for Apache DS.
|
||||
Please use <<servlet-authentication-ldap-unboundid,UnboundID>> instead.
|
||||
|
||||
[[servlet-authentication-ldap-contextsource]]
|
||||
== LDAP ContextSource
|
||||
|
@ -15,7 +15,7 @@ For example, adding the following element from the `security` namespace to an ap
|
||||
<security:ldap-server />
|
||||
----
|
||||
|
||||
This is much simpler than wiring up the equivalent Apache Directory Server beans.
|
||||
This is much simpler than wiring up the equivalent UnboundID Server beans.
|
||||
The most common alternative configuration requirements are supported by attributes on the `ldap-server` element, and the user is isolated from worrying about which beans they need to create and what the bean property names are.
|
||||
You can find out more about the use of the `ldap-server` element in the chapter on xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap[LDAP Authentication].
|
||||
A good XML editor while editing the application context file should provide information on the attributes and elements that are available.
|
||||
|
@ -45,7 +45,6 @@ dependencies {
|
||||
testImplementation libs.webauthn4j.core
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
|
||||
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
|
||||
testImplementation 'org.apache.directory.server:apacheds-core'
|
||||
testImplementation 'org.springframework:spring-core'
|
||||
testImplementation 'org.springframework:spring-test'
|
||||
|
||||
|
@ -4,7 +4,6 @@ io-rsocket = "1.1.5"
|
||||
io-spring-javaformat = "0.0.46"
|
||||
io-spring-nohttp = "0.0.11"
|
||||
jakarta-websocket = "2.2.0"
|
||||
org-apache-directory-server = "1.5.5"
|
||||
org-apache-maven-resolver = "1.9.23"
|
||||
org-aspectj = "1.9.24"
|
||||
org-bouncycastle = "1.80"
|
||||
@ -50,12 +49,6 @@ jakarta-xml-bind-jakarta-xml-bind-api = "jakarta.xml.bind:jakarta.xml.bind-api:4
|
||||
ldapsdk = "ldapsdk:ldapsdk:4.1"
|
||||
net-sourceforge-htmlunit = "net.sourceforge.htmlunit:htmlunit:2.70.0"
|
||||
org-htmlunit-htmlunit = "org.htmlunit:htmlunit:4.11.1"
|
||||
org-apache-directory-server-apacheds-core = { module = "org.apache.directory.server:apacheds-core", version.ref = "org-apache-directory-server" }
|
||||
org-apache-directory-server-apacheds-entry = { module = "org.apache.directory.server:apacheds-core-entry", version.ref = "org-apache-directory-server" }
|
||||
org-apache-directory-server-apacheds-protocol-ldap = { module = "org.apache.directory.server:apacheds-protocol-ldap", version.ref = "org-apache-directory-server" }
|
||||
org-apache-directory-server-apacheds-protocol-shared = { module = "org.apache.directory.server:apacheds-protocol-shared", version.ref = "org-apache-directory-server" }
|
||||
org-apache-directory-server-apacheds-server-jndi = { module = "org.apache.directory.server:apacheds-server-jndi", version.ref = "org-apache-directory-server" }
|
||||
org-apache-directory-shared-shared-ldap = "org.apache.directory.shared:shared-ldap:0.9.15"
|
||||
org-apache-httpcomponents-httpclient = "org.apache.httpcomponents:httpclient:4.5.14"
|
||||
org-apache-maven-maven-resolver-provider = "org.apache.maven:maven-resolver-provider:3.9.10"
|
||||
org-apache-maven-resolver-maven-resolver-connector-basic = { module = "org.apache.maven.resolver:maven-resolver-connector-basic", version.ref = "org-apache-maven-resolver" }
|
||||
|
@ -1,30 +0,0 @@
|
||||
apply plugin: 'io.spring.convention.spring-test'
|
||||
|
||||
dependencies {
|
||||
implementation platform(project(":spring-security-dependencies"))
|
||||
implementation project(':spring-security-core')
|
||||
implementation 'org.springframework:spring-beans'
|
||||
implementation 'org.springframework:spring-context'
|
||||
implementation 'org.springframework:spring-core'
|
||||
implementation 'org.springframework:spring-tx'
|
||||
implementation project(':spring-security-config')
|
||||
implementation project(':spring-security-ldap')
|
||||
|
||||
runtimeOnly "org.apache.directory.server:apacheds-core"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-core-entry"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-protocol-shared"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-server-jndi"
|
||||
runtimeOnly 'org.apache.directory.shared:shared-ldap'
|
||||
|
||||
testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
||||
testImplementation "org.mockito:mockito-core"
|
||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||
testImplementation "org.springframework:spring-test"
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParserTests {
|
||||
|
||||
private ClassPathXmlApplicationContext context;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void closeAppContext() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void apacheDirectoryServerIsStartedByDefault() {
|
||||
String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS);
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:s="http://www.springframework.org/schema/security"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<s:ldap-server ldif="classpath:users.ldif" port="0"/>
|
||||
|
||||
</beans>
|
@ -1,60 +0,0 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: uid=rod,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Rod Johnson
|
||||
sn: Johnson
|
||||
uid: rod
|
||||
userPassword: koala
|
||||
|
||||
dn: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Dianne Emu
|
||||
sn: Emu
|
||||
uid: dianne
|
||||
userPassword: emu
|
||||
|
||||
dn: uid=scott,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Scott
|
||||
sn: Wombat
|
||||
uid: scott
|
||||
userPassword: wombat
|
||||
|
||||
dn: cn=user,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: user
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
||||
member: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
member: uid=scott,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=teller,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: teller
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
||||
member: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=supervisor,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: supervisor
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
@ -1,30 +0,0 @@
|
||||
apply plugin: 'io.spring.convention.spring-test'
|
||||
|
||||
dependencies {
|
||||
implementation platform(project(":spring-security-dependencies"))
|
||||
implementation project(':spring-security-core')
|
||||
implementation 'org.springframework:spring-beans'
|
||||
implementation 'org.springframework:spring-context'
|
||||
implementation 'org.springframework:spring-core'
|
||||
implementation 'org.springframework:spring-tx'
|
||||
implementation project(':spring-security-config')
|
||||
implementation project(':spring-security-ldap')
|
||||
|
||||
runtimeOnly "org.apache.directory.server:apacheds-core"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-core-entry"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-protocol-shared"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-protocol-ldap"
|
||||
runtimeOnly "org.apache.directory.server:apacheds-server-jndi"
|
||||
runtimeOnly 'org.apache.directory.shared:shared-ldap'
|
||||
|
||||
testImplementation project(path : ':spring-security-ldap', configuration : 'tests')
|
||||
testImplementation "org.assertj:assertj-core"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-engine"
|
||||
testImplementation "org.mockito:mockito-core"
|
||||
testImplementation "org.mockito:mockito-junit-jupiter"
|
||||
testImplementation "org.springframework:spring-test"
|
||||
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2019 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParserTests {
|
||||
|
||||
private ClassPathXmlApplicationContext context;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.context = new ClassPathXmlApplicationContext("applicationContext-security.xml");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void closeAppContext() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
this.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void apacheDirectoryServerIsStartedByDefault() {
|
||||
String[] beanNames = this.context.getBeanNamesForType(ApacheDSContainer.class);
|
||||
assertThat(beanNames).hasSize(1);
|
||||
assertThat(beanNames[0]).isEqualTo(BeanIds.EMBEDDED_APACHE_DS);
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:s="http://www.springframework.org/schema/security"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.xsd">
|
||||
|
||||
<s:ldap-server mode="apacheds" ldif="classpath:users.ldif" port="0"/>
|
||||
|
||||
</beans>
|
@ -1,60 +0,0 @@
|
||||
dn: ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: people
|
||||
|
||||
dn: uid=rod,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Rod Johnson
|
||||
sn: Johnson
|
||||
uid: rod
|
||||
userPassword: koala
|
||||
|
||||
dn: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Dianne Emu
|
||||
sn: Emu
|
||||
uid: dianne
|
||||
userPassword: emu
|
||||
|
||||
dn: uid=scott,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Scott
|
||||
sn: Wombat
|
||||
uid: scott
|
||||
userPassword: wombat
|
||||
|
||||
dn: cn=user,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: user
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
||||
member: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
member: uid=scott,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=teller,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: teller
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
||||
member: uid=dianne,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=supervisor,ou=groups,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: supervisor
|
||||
member: uid=rod,ou=people,dc=springframework,dc=org
|
@ -15,12 +15,6 @@ dependencies {
|
||||
optional 'com.fasterxml.jackson.core:jackson-databind'
|
||||
optional 'ldapsdk:ldapsdk'
|
||||
optional "com.unboundid:unboundid-ldapsdk"
|
||||
optional "org.apache.directory.server:apacheds-core"
|
||||
optional "org.apache.directory.server:apacheds-core-entry"
|
||||
optional "org.apache.directory.server:apacheds-protocol-shared"
|
||||
optional "org.apache.directory.server:apacheds-protocol-ldap"
|
||||
optional "org.apache.directory.server:apacheds-server-jndi"
|
||||
optional 'org.apache.directory.shared:shared-ldap'
|
||||
api ('org.springframework.ldap:spring-ldap-core') {
|
||||
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||
exclude(group: 'org.springframework', module: 'spring-beans')
|
||||
|
@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class DefaultSpringSecurityContextSourceTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class SpringSecurityLdapTemplateITests {
|
||||
|
||||
@Autowired
|
||||
@ -116,10 +116,10 @@ public class SpringSecurityLdapTemplateITests {
|
||||
assertThat(values).hasSize(1);
|
||||
Map<String, List<String>> record = values.iterator().next();
|
||||
assertAttributeValue(record, "uid", "bob");
|
||||
assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson");
|
||||
assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson");
|
||||
assertAttributeValue(record, "cn", "Bob Hamilton");
|
||||
assertAttributeValue(record, "sn", "Hamilton");
|
||||
assertThat(record.containsKey("userPassword")).isFalse();
|
||||
assertThat(record.containsKey("userPassword")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -129,10 +129,10 @@ public class SpringSecurityLdapTemplateITests {
|
||||
assertThat(values).hasSize(1);
|
||||
Map<String, List<String>> record = values.iterator().next();
|
||||
assertAttributeValue(record, "uid", "bob");
|
||||
assertAttributeValue(record, "objectclass", "top", "person", "organizationalPerson", "inetOrgPerson");
|
||||
assertAttributeValue(record, "objectClass", "top", "person", "organizationalPerson", "inetOrgPerson");
|
||||
assertAttributeValue(record, "cn", "Bob Hamilton");
|
||||
assertAttributeValue(record, "sn", "Hamilton");
|
||||
assertThat(record.containsKey("userPassword")).isFalse();
|
||||
assertThat(record.containsKey("userPassword")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -145,7 +145,7 @@ public class SpringSecurityLdapTemplateITests {
|
||||
assertAttributeValue(record, "cn", "Bob Hamilton");
|
||||
assertAttributeValue(record, "sn", "Hamilton");
|
||||
assertThat(record.containsKey("userPassword")).isFalse();
|
||||
assertThat(record.containsKey("objectclass")).isFalse();
|
||||
assertThat(record.containsKey("objectClass")).isFalse();
|
||||
}
|
||||
|
||||
protected void assertAttributeValue(Map<String, List<String>> record, String attributeName, String... values) {
|
||||
|
@ -20,31 +20,31 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
|
||||
/**
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration
|
||||
public class ApacheDsContainerConfig implements DisposableBean {
|
||||
public class UnboundIdContainerConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapContainer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
UnboundIdContainer ldapContainer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ContextSource contextSource(ApacheDSContainer ldapContainer) throws Exception {
|
||||
ContextSource contextSource(UnboundIdContainer ldapContainer) {
|
||||
return new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org");
|
||||
"ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
public void destroy() {
|
||||
this.container.stop();
|
||||
}
|
||||
|
@ -33,8 +33,8 @@ import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
@ -53,7 +53,7 @@ import static org.mockito.Mockito.spy;
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class BindAuthenticatorTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -30,8 +30,8 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.keygen.KeyGenerators;
|
||||
import org.springframework.security.crypto.password.LdapShaPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class PasswordComparisonAuthenticatorTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -25,8 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class FilterBasedLdapUserSearchTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -40,7 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Steve Riesenberg
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.ApacheDsContainerWithSpacesConfig.class)
|
||||
@ContextConfiguration(classes = FilterBasedLdapUserSearchWithSpacesTests.UnboundIdContainerWithSpacesConfig.class)
|
||||
public class FilterBasedLdapUserSearchWithSpacesTests {
|
||||
|
||||
@Autowired
|
||||
@ -61,22 +61,22 @@ public class FilterBasedLdapUserSearchWithSpacesTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ApacheDsContainerWithSpacesConfig implements DisposableBean {
|
||||
static class UnboundIdContainerWithSpacesConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapContainer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=spring framework,dc=org",
|
||||
UnboundIdContainer ldapContainer() {
|
||||
this.container = new UnboundIdContainer("dc=spring framework,dc=org",
|
||||
"classpath:test-server-with-spaces.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ContextSource contextSource(ApacheDSContainer ldapContainer) {
|
||||
ContextSource contextSource(UnboundIdContainer ldapContainer) {
|
||||
return new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=spring%20framework,dc=org");
|
||||
"ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=spring%20framework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2020 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Useful for debugging the container by itself.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
* @author Gunnar Hillert
|
||||
* @author Evgeniy Cheban
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ApacheDSContainerTests {
|
||||
|
||||
@TempDir
|
||||
public File temporaryFolder;
|
||||
|
||||
// SEC-2162
|
||||
@Test
|
||||
public void failsToStartThrowsException() throws Exception {
|
||||
ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:missing.ldif");
|
||||
List<Integer> ports = getDefaultPorts(1);
|
||||
server1.setPort(ports.get(0));
|
||||
server2.setPort(ports.get(0));
|
||||
try {
|
||||
server1.afterPropertiesSet();
|
||||
try {
|
||||
server2.afterPropertiesSet();
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (RuntimeException success) {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
server1.destroy();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
}
|
||||
try {
|
||||
server2.destroy();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-2161
|
||||
@Test
|
||||
public void multipleInstancesSimultanciously() throws Exception {
|
||||
ApacheDSContainer server1 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
ApacheDSContainer server2 = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
List<Integer> ports = getDefaultPorts(2);
|
||||
server1.setPort(ports.get(0));
|
||||
server2.setPort(ports.get(1));
|
||||
try {
|
||||
server1.afterPropertiesSet();
|
||||
server2.afterPropertiesSet();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
server1.destroy();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
}
|
||||
try {
|
||||
server2.destroy();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithLdapOverSslWithoutCertificate() throws Exception {
|
||||
ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
List<Integer> ports = getDefaultPorts(1);
|
||||
server.setPort(ports.get(0));
|
||||
server.setLdapOverSslEnabled(true);
|
||||
assertThatIllegalArgumentException().isThrownBy(server::afterPropertiesSet)
|
||||
.withMessage("When LdapOverSsl is enabled, the keyStoreFile property must be set.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnOs(OS.WINDOWS)
|
||||
public void startWithLdapOverSslWithWrongPassword() throws Exception {
|
||||
final ClassPathResource keyStoreResource = new ClassPathResource(
|
||||
"/org/springframework/security/ldap/server/spring.keystore");
|
||||
final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore");
|
||||
FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile));
|
||||
|
||||
assertThat(temporaryKeyStoreFile).isFile();
|
||||
|
||||
ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
|
||||
List<Integer> ports = getDefaultPorts(1);
|
||||
server.setPort(ports.get(0));
|
||||
|
||||
server.setLdapOverSslEnabled(true);
|
||||
server.setKeyStoreFile(temporaryKeyStoreFile);
|
||||
server.setCertificatePassord("incorrect-password");
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(server::afterPropertiesSet)
|
||||
.withMessage("Server startup failed")
|
||||
.withRootCauseInstanceOf(UnrecoverableKeyException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test starts an LDAP server using LDAPs (LDAP over SSL). A self-signed
|
||||
* certificate is being used, which was previously generated with:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* keytool -genkey -alias spring -keyalg RSA -keystore spring.keystore -validity 3650 -storetype JKS \
|
||||
* -dname "CN=localhost, OU=Spring, O=Pivotal, L=Kailua-Kona, ST=HI, C=US" -keypass spring -storepass spring
|
||||
* }
|
||||
* </pre>
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@DisabledOnOs(OS.WINDOWS)
|
||||
public void startWithLdapOverSsl() throws Exception {
|
||||
|
||||
final ClassPathResource keyStoreResource = new ClassPathResource(
|
||||
"/org/springframework/security/ldap/server/spring.keystore");
|
||||
final File temporaryKeyStoreFile = new File(this.temporaryFolder, "spring.keystore");
|
||||
FileCopyUtils.copy(keyStoreResource.getInputStream(), new FileOutputStream(temporaryKeyStoreFile));
|
||||
|
||||
assertThat(temporaryKeyStoreFile).isFile();
|
||||
|
||||
ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
|
||||
List<Integer> ports = getDefaultPorts(1);
|
||||
server.setPort(ports.get(0));
|
||||
|
||||
server.setLdapOverSslEnabled(true);
|
||||
server.setKeyStoreFile(temporaryKeyStoreFile);
|
||||
server.setCertificatePassord("spring");
|
||||
|
||||
try {
|
||||
server.afterPropertiesSet();
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
server.destroy();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Integer> getDefaultPorts(int count) throws IOException {
|
||||
List<ServerSocket> connections = new ArrayList<>();
|
||||
List<Integer> availablePorts = new ArrayList<>(count);
|
||||
try {
|
||||
for (int i = 0; i < count; i++) {
|
||||
ServerSocket socket = new ServerSocket(0);
|
||||
connections.add(socket);
|
||||
availablePorts.add(socket.getLocalPort());
|
||||
}
|
||||
return availablePorts;
|
||||
}
|
||||
finally {
|
||||
for (ServerSocket conn : connections) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterPropertiesSetWhenPortIsZeroThenRandomPortIsSelected() throws Exception {
|
||||
ApacheDSContainer server = new ApacheDSContainer("dc=springframework,dc=org", "classpath:test-server.ldif");
|
||||
server.setPort(0);
|
||||
try {
|
||||
server.afterPropertiesSet();
|
||||
|
||||
assertThat(server.getPort()).isEqualTo(0);
|
||||
assertThat(server.getLocalPort()).isNotEqualTo(0);
|
||||
}
|
||||
finally {
|
||||
server.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.server;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ldap.core.support.LdapContextSource;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests reproducing problems with loading structures from ldif on embedded ApacheDS
|
||||
* server.
|
||||
*
|
||||
* @author Marcin Zajączkowski
|
||||
*/
|
||||
public class ApacheDSEmbeddedLdifTests {
|
||||
|
||||
private static final String LDAP_ROOT = "ou=ssattributes,dc=springframework,dc=org";
|
||||
|
||||
private static final int LDAP_PORT = 52389;
|
||||
|
||||
private ApacheDSContainer server;
|
||||
|
||||
private SpringSecurityLdapTemplate ldapTemplate;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
// TODO: InMemoryXmlApplicationContext would be useful here, but it is not visible
|
||||
this.server = new ApacheDSContainer(LDAP_ROOT, "classpath:test-server-custom-attribute-types.ldif");
|
||||
this.server.setPort(LDAP_PORT);
|
||||
this.server.afterPropertiesSet();
|
||||
|
||||
this.ldapTemplate = new SpringSecurityLdapTemplate(createLdapContextSource());
|
||||
}
|
||||
|
||||
private LdapContextSource createLdapContextSource() {
|
||||
LdapContextSource ldapContextSource = new LdapContextSource();
|
||||
ldapContextSource.setUrl("ldap://localhost:" + LDAP_PORT);
|
||||
ldapContextSource.setBase(LDAP_ROOT);
|
||||
ldapContextSource.afterPropertiesSet();
|
||||
return ldapContextSource;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() throws Exception {
|
||||
if (this.server != null) {
|
||||
this.server.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Disabled // Not fixed yet
|
||||
@Test // SEC-2387
|
||||
public void customAttributeTypesShouldBeProperlyCreatedWhenLoadedFromLdif() {
|
||||
assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "uid", "objectWithCustomAttribute1"))
|
||||
.isTrue();
|
||||
assertThat(this.ldapTemplate.compare("uid=objectWithCustomAttribute1", "customAttribute", "I am custom"))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,7 @@ import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.ldap.server.ApacheDSContainer;
|
||||
import org.springframework.security.ldap.server.UnboundIdContainer;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(
|
||||
classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.ApacheDsContainerWithUndefinedGroupRoleAttributeConfig.class)
|
||||
classes = DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests.UnboundIdContainerWithUndefinedGroupRoleAttributeConfig.class)
|
||||
public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests {
|
||||
|
||||
@Autowired
|
||||
@ -77,22 +77,22 @@ public class DefaultLdapAuthoritiesPopulatorGetGrantedAuthoritiesTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class ApacheDsContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean {
|
||||
static class UnboundIdContainerWithUndefinedGroupRoleAttributeConfig implements DisposableBean {
|
||||
|
||||
private ApacheDSContainer container;
|
||||
private UnboundIdContainer container;
|
||||
|
||||
@Bean
|
||||
ApacheDSContainer ldapContainer() throws Exception {
|
||||
this.container = new ApacheDSContainer("dc=springframework,dc=org",
|
||||
UnboundIdContainer ldapContainer() {
|
||||
this.container = new UnboundIdContainer("dc=springframework,dc=org",
|
||||
"classpath:test-server-with-undefined-group-role-attributes.ldif");
|
||||
this.container.setPort(0);
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ContextSource contextSource(ApacheDSContainer ldapContainer) {
|
||||
ContextSource contextSource(UnboundIdContainer ldapContainer) {
|
||||
return new DefaultSpringSecurityContextSource(
|
||||
"ldap://127.0.0.1:" + ldapContainer.getLocalPort() + "/dc=springframework,dc=org");
|
||||
"ldap://127.0.0.1:" + ldapContainer.getPort() + "/dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -31,8 +31,8 @@ import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -44,7 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
@SuppressWarnings({ "deprecation" })
|
||||
public class DefaultLdapAuthoritiesPopulatorTests {
|
||||
|
||||
|
@ -34,9 +34,9 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -52,7 +52,7 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Roman Zabaluev
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class LdapUserDetailsManagerTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -28,7 +28,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.ldap.ApacheDsContainerConfig;
|
||||
import org.springframework.security.ldap.UnboundIdContainerConfig;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = ApacheDsContainerConfig.class)
|
||||
@ContextConfiguration(classes = UnboundIdContainerConfig.class)
|
||||
public class NestedLdapAuthoritiesPopulatorTests {
|
||||
|
||||
@Autowired
|
||||
|
@ -1,365 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.ldap.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.directory.server.core.DefaultDirectoryService;
|
||||
import org.apache.directory.server.core.authn.AuthenticationInterceptor;
|
||||
import org.apache.directory.server.core.entry.ServerEntry;
|
||||
import org.apache.directory.server.core.exception.ExceptionInterceptor;
|
||||
import org.apache.directory.server.core.interceptor.Interceptor;
|
||||
import org.apache.directory.server.core.normalization.NormalizationInterceptor;
|
||||
import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
|
||||
import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
|
||||
import org.apache.directory.server.core.referral.ReferralInterceptor;
|
||||
import org.apache.directory.server.core.subtree.SubentryInterceptor;
|
||||
import org.apache.directory.server.ldap.LdapServer;
|
||||
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
|
||||
import org.apache.directory.server.protocol.shared.transport.TcpTransport;
|
||||
import org.apache.directory.shared.ldap.exception.LdapNameNotFoundException;
|
||||
import org.apache.directory.shared.ldap.name.LdapDN;
|
||||
import org.apache.mina.transport.socket.SocketAcceptor;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Provides lifecycle services for the embedded apacheDS server defined by the supplied
|
||||
* configuration. Used by {@code LdapServerBeanDefinitionParser}. An instance will be
|
||||
* stored in the application context for each embedded server instance. It will start the
|
||||
* server when the context is initialized and shut it down when it is closed. It is
|
||||
* intended for temporary embedded use and will not retain changes across start/stop
|
||||
* boundaries. The working directory is deleted on shutdown.
|
||||
*
|
||||
* <p>
|
||||
* If used repeatedly in a single JVM process with the same configuration (for example,
|
||||
* when repeatedly loading an application context during testing), it's important that the
|
||||
* application context is closed to allow the bean to be disposed of and the server
|
||||
* shutdown prior to attempting to start it again.
|
||||
* <p>
|
||||
* This class is intended for testing and internal security namespace use, only, and is
|
||||
* not considered part of the framework's public API.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Rob Winch
|
||||
* @author Gunnar Hillert
|
||||
* @author Evgeniy Cheban
|
||||
* @deprecated For removal in 7.0. Use {@link UnboundIdContainer} instead because ApacheDS
|
||||
* 1.x is no longer supported with no GA version to replace it.
|
||||
*/
|
||||
@Deprecated(since = "5.2", forRemoval = true)
|
||||
public class ApacheDSContainer
|
||||
implements EmbeddedLdapServerContainer, InitializingBean, DisposableBean, Lifecycle, ApplicationContextAware {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
final DefaultDirectoryService service;
|
||||
|
||||
LdapServer server;
|
||||
|
||||
private TcpTransport transport;
|
||||
|
||||
private ApplicationContext ctxt;
|
||||
|
||||
private File workingDir;
|
||||
|
||||
private boolean running;
|
||||
|
||||
private final String ldifResources;
|
||||
|
||||
private final JdbmPartition partition;
|
||||
|
||||
private final String root;
|
||||
|
||||
private int port = 53389;
|
||||
|
||||
private int localPort;
|
||||
|
||||
private boolean ldapOverSslEnabled;
|
||||
|
||||
private File keyStoreFile;
|
||||
|
||||
private String certificatePassord;
|
||||
|
||||
public ApacheDSContainer(String root, String ldifs) throws Exception {
|
||||
this.ldifResources = ldifs;
|
||||
this.service = new DefaultDirectoryService();
|
||||
List<Interceptor> list = new ArrayList<>();
|
||||
list.add(new NormalizationInterceptor());
|
||||
list.add(new AuthenticationInterceptor());
|
||||
list.add(new ReferralInterceptor());
|
||||
list.add(new ExceptionInterceptor());
|
||||
list.add(new OperationalAttributeInterceptor());
|
||||
list.add(new SubentryInterceptor());
|
||||
this.service.setInterceptors(list);
|
||||
this.partition = new JdbmPartition();
|
||||
this.partition.setId("rootPartition");
|
||||
this.partition.setSuffix(root);
|
||||
this.root = root;
|
||||
this.service.addPartition(this.partition);
|
||||
this.service.setExitVmOnShutdown(false);
|
||||
this.service.setShutdownHookEnabled(false);
|
||||
this.service.getChangeLog().setEnabled(false);
|
||||
this.service.setDenormalizeOpAttrsEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.workingDir == null) {
|
||||
String apacheWorkDir = System.getProperty("apacheDSWorkDir");
|
||||
if (apacheWorkDir == null) {
|
||||
apacheWorkDir = createTempDirectory("apacheds-spring-security-");
|
||||
}
|
||||
setWorkingDirectory(new File(apacheWorkDir));
|
||||
}
|
||||
Assert.isTrue(!this.ldapOverSslEnabled || this.keyStoreFile != null,
|
||||
"When LdapOverSsl is enabled, the keyStoreFile property must be set.");
|
||||
this.server = new LdapServer();
|
||||
this.server.setDirectoryService(this.service);
|
||||
// AbstractLdapIntegrationTests assume IPv4, so we specify the same here
|
||||
this.transport = new TcpTransport(this.port);
|
||||
if (this.ldapOverSslEnabled) {
|
||||
this.transport.setEnableSSL(true);
|
||||
this.server.setKeystoreFile(this.keyStoreFile.getAbsolutePath());
|
||||
this.server.setCertificatePassword(this.certificatePassord);
|
||||
}
|
||||
this.server.setTransports(this.transport);
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.ctxt = applicationContext;
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(File workingDir) {
|
||||
Assert.notNull(workingDir, "workingDir cannot be null");
|
||||
this.logger.info("Setting working directory for LDAP_PROVIDER: " + workingDir.getAbsolutePath());
|
||||
Assert.isTrue(!workingDir.exists(),
|
||||
"The specified working directory '" + workingDir.getAbsolutePath()
|
||||
+ "' already exists. Another directory service instance may be using it or it may be from a "
|
||||
+ " previous unclean shutdown. Please confirm and delete it or configure a different "
|
||||
+ "working directory");
|
||||
this.workingDir = workingDir;
|
||||
this.service.setWorkingDirectory(workingDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port that is resolved by {@link TcpTransport}.
|
||||
* @return the port that is resolved by {@link TcpTransport}
|
||||
*/
|
||||
public int getLocalPort() {
|
||||
return this.localPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true} will enable LDAP over SSL (LDAPs). If set to {@code true}
|
||||
* {@link ApacheDSContainer#setCertificatePassord(String)} must be set as well.
|
||||
* @param ldapOverSslEnabled If not set, will default to false
|
||||
*/
|
||||
public void setLdapOverSslEnabled(boolean ldapOverSslEnabled) {
|
||||
this.ldapOverSslEnabled = ldapOverSslEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* The keyStore must not be null and must be a valid file. Will set the keyStore file
|
||||
* on the underlying {@link LdapServer}.
|
||||
* @param keyStoreFile Mandatory if LDAPs is enabled
|
||||
*/
|
||||
public void setKeyStoreFile(File keyStoreFile) {
|
||||
Assert.notNull(keyStoreFile, "The keyStoreFile must not be null.");
|
||||
Assert.isTrue(keyStoreFile.isFile(), "The keyStoreFile must be a file.");
|
||||
this.keyStoreFile = keyStoreFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will set the certificate password on the underlying {@link LdapServer}.
|
||||
* @param certificatePassord May be null
|
||||
*/
|
||||
public void setCertificatePassord(String certificatePassord) {
|
||||
this.certificatePassord = certificatePassord;
|
||||
}
|
||||
|
||||
public DefaultDirectoryService getService() {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (isRunning()) {
|
||||
return;
|
||||
}
|
||||
Assert.state(!this.service.isStarted(), "DirectoryService is already running.");
|
||||
this.logger.info("Starting directory server...");
|
||||
try {
|
||||
this.service.startup();
|
||||
this.server.start();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException("Server startup failed", ex);
|
||||
}
|
||||
try {
|
||||
this.service.getAdminSession().lookup(this.partition.getSuffixDn());
|
||||
}
|
||||
catch (LdapNameNotFoundException ex) {
|
||||
handleLdapNameNotFoundException();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.error("Lookup failed", ex);
|
||||
}
|
||||
SocketAcceptor socketAcceptor = this.server.getSocketAcceptor(this.transport);
|
||||
InetSocketAddress localAddress = socketAcceptor.getLocalAddress();
|
||||
this.localPort = localAddress.getPort();
|
||||
this.running = true;
|
||||
try {
|
||||
importLdifs();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to import LDIF file(s)", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLdapNameNotFoundException() {
|
||||
try {
|
||||
LdapDN dn = new LdapDN(this.root);
|
||||
Assert.isTrue(this.root.startsWith("dc="), "root must start with dc=");
|
||||
String dc = this.root.substring(3, this.root.indexOf(','));
|
||||
ServerEntry entry = this.service.newEntry(dn);
|
||||
entry.add("objectClass", "top", "domain", "extensibleObject");
|
||||
entry.add("dc", dc);
|
||||
this.service.getAdminSession().add(entry);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.error("Failed to create dc entry", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (!isRunning()) {
|
||||
return;
|
||||
}
|
||||
this.logger.info("Shutting down directory server ...");
|
||||
try {
|
||||
this.server.stop();
|
||||
this.service.shutdown();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
this.logger.error("Shutdown failed", ex);
|
||||
return;
|
||||
}
|
||||
this.running = false;
|
||||
if (this.workingDir.exists()) {
|
||||
this.logger.info("Deleting working directory " + this.workingDir.getAbsolutePath());
|
||||
deleteDir(this.workingDir);
|
||||
}
|
||||
}
|
||||
|
||||
private void importLdifs() throws Exception {
|
||||
// Import any ldif files
|
||||
Resource[] ldifs = (this.ctxt != null) ? this.ctxt.getResources(this.ldifResources)
|
||||
: new PathMatchingResourcePatternResolver().getResources(this.ldifResources);
|
||||
// Note that we can't just import using the ServerContext returned
|
||||
// from starting Apache DS, apparently because of the long-running issue
|
||||
// DIRSERVER-169.
|
||||
// We need a standard context.
|
||||
// DirContext dirContext = contextSource.getReadWriteContext();
|
||||
if (ldifs == null || ldifs.length == 0) {
|
||||
return;
|
||||
}
|
||||
Assert.isTrue(ldifs.length == 1, () -> "More than one LDIF resource found with the supplied pattern:"
|
||||
+ this.ldifResources + " Got " + Arrays.toString(ldifs));
|
||||
String ldifFile = getLdifFile(ldifs);
|
||||
this.logger.info("Loading LDIF file: " + ldifFile);
|
||||
LdifFileLoader loader = new LdifFileLoader(this.service.getAdminSession(), new File(ldifFile), null,
|
||||
getClass().getClassLoader());
|
||||
loader.execute();
|
||||
}
|
||||
|
||||
private String getLdifFile(Resource[] ldifs) throws IOException {
|
||||
try {
|
||||
return ldifs[0].getFile().getAbsolutePath();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return ldifs[0].getURI().toString();
|
||||
}
|
||||
}
|
||||
|
||||
private String createTempDirectory(String prefix) throws IOException {
|
||||
String parentTempDir = System.getProperty("java.io.tmpdir");
|
||||
String fileNamePrefix = prefix + System.nanoTime();
|
||||
String fileName = fileNamePrefix;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
File tempDir = new File(parentTempDir, fileName);
|
||||
if (!tempDir.exists()) {
|
||||
return tempDir.getAbsolutePath();
|
||||
}
|
||||
fileName = fileNamePrefix + "~" + i;
|
||||
}
|
||||
throw new IOException(
|
||||
"Failed to create a temporary directory for file at " + new File(parentTempDir, fileNamePrefix));
|
||||
}
|
||||
|
||||
private boolean deleteDir(File dir) {
|
||||
if (dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
for (String child : children) {
|
||||
boolean success = deleteDir(new File(dir, child));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
}
|
@ -15,7 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Embedded Apache Directory Server implementation, as used by the configuration
|
||||
* namespace.
|
||||
* Embedded UnboundID Server implementation, as used by the configuration namespace.
|
||||
*/
|
||||
package org.springframework.security.ldap.server;
|
||||
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.directory.server.core.avltree;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.directory.shared.ldap.util.StringTools;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class to serialize the Array data.
|
||||
*
|
||||
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
|
||||
* @version $Rev$, $Date$
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ArrayMarshaller<E> implements Marshaller<ArrayTree<E>> {
|
||||
|
||||
/** static logger */
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ArrayMarshaller.class);
|
||||
|
||||
/** used for serialized form of an empty AvlTree */
|
||||
private static final byte[] EMPTY_TREE = new byte[1];
|
||||
|
||||
/** marshaller to be used for marshalling the keys */
|
||||
private Marshaller<E> keyMarshaller;
|
||||
|
||||
/** key Comparator for the AvlTree */
|
||||
private Comparator<E> comparator;
|
||||
|
||||
/**
|
||||
* Creates a new instance of AvlTreeMarshaller with a custom key Marshaller.
|
||||
* @param comparator Comparator to be used for key comparision
|
||||
* @param keyMarshaller marshaller for keys
|
||||
*/
|
||||
public ArrayMarshaller(Comparator<E> comparator, Marshaller<E> keyMarshaller) {
|
||||
this.comparator = comparator;
|
||||
this.keyMarshaller = keyMarshaller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of AvlTreeMarshaller with the default key Marshaller which
|
||||
* uses Java Serialization.
|
||||
* @param comparator Comparator to be used for key comparision
|
||||
*/
|
||||
public ArrayMarshaller(Comparator<E> comparator) {
|
||||
this.comparator = comparator;
|
||||
this.keyMarshaller = DefaultMarshaller.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshals the given tree to bytes
|
||||
* @param tree the tree to be marshalled
|
||||
*/
|
||||
public byte[] serialize(ArrayTree<E> tree) {
|
||||
if ((tree == null) || tree.isEmpty()) {
|
||||
return EMPTY_TREE;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(byteStream);
|
||||
byte[] data = null;
|
||||
|
||||
try {
|
||||
out.writeByte(0); // represents the start of an Array byte stream
|
||||
out.writeInt(tree.size());
|
||||
|
||||
for (int position = 0; position < tree.size(); position++) {
|
||||
E value = tree.get(position);
|
||||
byte[] bytes = this.keyMarshaller.serialize(value);
|
||||
|
||||
// Write the key length
|
||||
out.writeInt(bytes.length);
|
||||
|
||||
// Write the key if its length is not null
|
||||
if (bytes.length != 0) {
|
||||
out.write(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
out.flush();
|
||||
data = byteStream.toByteArray();
|
||||
|
||||
// Try to deserialize, just to see
|
||||
try {
|
||||
deserialize(data);
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
System.out.println("Bad serialization, tree : [" + StringTools.dumpBytes(data) + "]");
|
||||
throw npe;
|
||||
}
|
||||
|
||||
out.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an Array from given bytes of data.
|
||||
* @param data byte array to be converted into an array
|
||||
*/
|
||||
public ArrayTree<E> deserialize(byte[] data) throws IOException {
|
||||
try {
|
||||
if ((data == null) || (data.length == 0)) {
|
||||
throw new IOException("Null or empty data array is invalid.");
|
||||
}
|
||||
|
||||
if ((data.length == 1) && (data[0] == 0)) {
|
||||
E[] array = (E[]) new Object[] {};
|
||||
ArrayTree<E> tree = new ArrayTree<E>(this.comparator, array);
|
||||
return tree;
|
||||
}
|
||||
|
||||
ByteArrayInputStream bin = new ByteArrayInputStream(data);
|
||||
DataInputStream din = new DataInputStream(bin);
|
||||
|
||||
byte startByte = din.readByte();
|
||||
|
||||
if (startByte != 0) {
|
||||
throw new IOException("wrong array serialized data format");
|
||||
}
|
||||
|
||||
int size = din.readInt();
|
||||
E[] nodes = (E[]) new Object[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
// Read the object's size
|
||||
int dataSize = din.readInt();
|
||||
|
||||
if (dataSize != 0) {
|
||||
byte[] bytes = new byte[dataSize];
|
||||
|
||||
din.read(bytes);
|
||||
E key = this.keyMarshaller.deserialize(bytes);
|
||||
nodes[i] = key;
|
||||
}
|
||||
}
|
||||
|
||||
ArrayTree<E> arrayTree = new ArrayTree<E>(this.comparator, nodes);
|
||||
|
||||
return arrayTree;
|
||||
}
|
||||
catch (NullPointerException npe) {
|
||||
System.out.println("Bad tree : [" + StringTools.dumpBytes(data) + "]");
|
||||
throw npe;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,6 @@ import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
import org.apache.directory.shared.ldap.util.EmptyEnumeration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@ -175,7 +174,7 @@ public class ActiveDirectoryLdapAuthenticationProviderTests {
|
||||
@Test
|
||||
public void noUserSearchCausesUsernameNotFound() throws Exception {
|
||||
given(this.ctx.search(any(Name.class), any(String.class), any(Object[].class), any(SearchControls.class)))
|
||||
.willReturn(new EmptyEnumeration<>());
|
||||
.willReturn(new MockNamingEnumeration(null));
|
||||
this.provider.contextFactory = createContextFactoryReturning(this.ctx);
|
||||
assertThatExceptionOfType(BadCredentialsException.class).isThrownBy(() -> this.provider.authenticate(this.joe));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user