I am trying to setup embedded ldap for unit test with Spring Ldap. But I need to use a custom schema for custom objectClasses/attributes definitions. How can I configure it with Spring Ldap test (LdapTestUtils?)
Actually if I run test, it fail saying that my custom objectClass "myOb" is not defined in the schema with the following message :
org.springframework.ldap.UncategorizedLdapException: Failed to populate LDIF; nested exception is javax.naming.directory.NoSuchAttributeException: [LDAP: error code 16 - NO_SUCH_ATTRIBUTE: failed for Add Request :
...
: OID for name 'myOb' was not found within the OID registry]; remaining name 'cn=123456, ou=MyUser, o=company.com'
If I comment objectClass: myOb
from ldif, the test fail with a null value (attribute is not read).
Here is my test class :
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = LdapConfiguration.class, loader = AnnotationConfigContextLoader.class)
public class LdapTest {
// Ldap port
private static final int LDAP_PORT = 18880;
// Base DN for test data
private static final LdapName baseName = LdapUtils.newLdapName("o=company.com");
@Autowired
LdapTemplate ldapTemplate;
@BeforeClass
public static void setupBeforeClass() {
LdapTestUtils.startEmbeddedServer(LDAP_PORT, baseName.toString(), "ldaptest");
// How to load schema definition ?
}
@AfterClass
public static void teardownAfterClass() throws Exception {
LdapTestUtils.shutdownEmbeddedServer();
}
@Before
public void setup() throws Exception {
LdapTestUtils.cleanAndSetup(ldapTemplate.getContextSource(), baseName, new ClassPathResource("ldap/test-users.ldif"));
}
@Test
public void testSearchLdap() throws Exception {
String myObId = ldapTemplate.lookup(LdapNameBuilder.newInstance("ou=MyUser, o=company.com").add("cn", "123456").build(), new AbstractContextMapper<String>() {
@Override
protected String doMapFromContext(DirContextOperations ctx) {
return ctx.getStringAttribute("myObId"); // custom type
}
});
Assert.assertNotNull(myObId); // myObId is null if I comment `objectClass: myOb` !
}
}
and my ldif :
dn: ou=MyUser, o=company.com
ou: User
description: MyUser
objectClass: top
objectClass: organizationalunit
dn: cn=123456, ou=MyUser, o=company.com
objectClass: top
objectClass: person
objectClass: myOb
cn: 123456
sn: 823456
myObId: TEST
I don't know how to do it with Spring Ldap... But I use Unboundid InMemoryDirectoryServer in my unit tests. This implementation of the server doesn't restrict any custom objectClasses/attributes definitions. If you want, I can share my JUnitRule here. The rule starts InMemory server and loads a ldiff into it
UPDATED:
public class LdapServerRule extends ExternalResource {
private static final Log LOG = LogFactory
.getLog(LdapServerRule.class);
public static final String DefaultDn = "cn=Directory Manager";
public static final String DefaultPassword = "password";
private String baseDn;
private String dn;
private String password;
private String lDiffPath;
private InMemoryDirectoryServer server;
private int listenPort;
public LdapServerRule(String baseDn, String lDiffPath) {
this(baseDn, lDiffPath, 0);
}
public LdapServerRule(String baseDn, String lDiffPath, int listenPort) {
this.lDiffPath = lDiffPath;
this.baseDn = baseDn;
this.dn = DefaultDn;
this.password = DefaultPassword;
this.listenPort = listenPort;
}
@Override
protected void before() {
start();
}
@Override
protected void after() {
stop();
}
public int getRunningPort() {
return getServer().getListenPort();
}
private void start() {
InMemoryDirectoryServerConfig config;
try {
LOG.info("LDAP server " + toString() + " starting...");
config = new InMemoryDirectoryServerConfig(getBaseDn());
config.addAdditionalBindCredentials(getDn(),
getPassword());
config.setSchema(null);
config.setListenerConfigs(
InMemoryListenerConfig.createLDAPConfig("LDAP", getListenPort()));
setServer(new InMemoryDirectoryServer(config));
getServer().importFromLDIF(true, getLDiffPath());
getServer().startListening();
LOG.info("LDAP server " + toString() + " started. Listen on port " + getServer().getListenPort());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void stop() {
server.shutDown(true);
LOG.info("LDAP server " + toString() + " stopped");
}
public String getBaseDn() {
return baseDn;
}
public String getDn() {
return dn;
}
public String getPassword() {
return password;
}
public InMemoryDirectoryServer getServer() {
return server;
}
public void setServer(InMemoryDirectoryServer server) {
this.server = server;
}
public String getLDiffPath() {
return lDiffPath;
}
public int getListenPort() {
return listenPort;
}
@Override
public String toString() {
return com.google.common.base.Objects.toStringHelper(this)
.add("baseDn", baseDn)
.add("listenPort", listenPort)
.toString();
}
}
You can use this rule like this
@ClassRule
public static final LdapServerRule LDAP_RULE =
new LdapServerRule("dc=mmkauth", resourceFilePath("data.ldiff"));
LDAP_RULE.getListenPort() returns actual port for connection, or you can pass the port directly into the constructor
Spring Boot provides two properties to either ignore the schema or set the path of the schema file:
spring.ldap.embedded.validation.enabled=true # Whether to enable LDAP schema validation.
spring.ldap.embedded.validation.schema= # Path to the custom schema.
@See common-application-properties
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With