Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Ldap unit testing with custom schema definition

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
like image 428
Aure77 Avatar asked Dec 17 '14 17:12

Aure77


2 Answers

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

like image 165
Dmitry Zaytsev Avatar answered Sep 20 '22 06:09

Dmitry Zaytsev


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

like image 20
fuxiang Avatar answered Sep 20 '22 06:09

fuxiang