Gooday,
Im having a rather bizarre problem with Spring-LDAP what in its essence seems more a JSNI problem then a Spring problem.
The Problem:
I have the following LDAP structure:
dc=company,dc=com,dc=productname
|-o=TESTORG1
| |-ou=UserGroupName
| |-ou=users
| |-ou=user1@TESTORG1
|-o=TESTORG2
| |-ou=User/Group/Name
| |-ou=users
| |-ou=user1@TESTORG2
So I can create this all quite neatly with LdapTemplate given trough Spring. However I run in to some weird problems if I try to recursively delete an organisation.
@Test
public void createSimpleOrganisationWithSpecialChars() throws NamingException {
LdapOrganisation originalOrg = new LdapOrganisation("TESTORG2");
LdapUserGroup userGroup = new LdapUserGroup("User/Group/Name");
userGroup.addUser(new User("user1",originalOrg ));
originalOrg.addUserGroup(userGroup);
dataAccess.updateLdap(originalOrg);
OrganisationDao org = new OrganisationDao(this.ldapTemplate);
org.unbind(organisation,true);
}
The implementation of the unbind is as follows:
public void unbind(LdapOrganisation organisation, boolean recursive) {
if(organisation != null) {
DirContextAdapter context = new DirContextAdapter(buildDn(organisation));
mapToContext(organisation, context);
ldapTemplate.unbind(context.getDn(), recursive);
}
}
Now if I run this code I get the following error:
org.springframework.ldap.InvalidNameException: Invalid name: "ou=User/Group/Name"; nested exception is javax.naming.InvalidNameException: Invalid name: "ou=User/Group/Name"
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:136)
at org.springframework.ldap.support.LdapUtils.newLdapName(LdapUtils.java:416)
at org.springframework.ldap.core.LdapTemplate.deleteRecursively(LdapTemplate.java:1103)
at org.springframework.ldap.core.LdapTemplate$25.executeWithContext(LdapTemplate.java:1074)
at org.springframework.ldap.core.LdapTemplate.executeWithContext(LdapTemplate.java:817)
at org.springframework.ldap.core.LdapTemplate.executeReadWrite(LdapTemplate.java:812)
at org.springframework.ldap.core.LdapTemplate.doUnbindRecursively(LdapTemplate.java:1072)
at org.springframework.ldap.core.LdapTemplate.unbind(LdapTemplate.java:1036)
at net.thadir.dataservices.ldap.dao.OrganisationDao.unbind(OrganisationDao.java:108)
at net.thadir.dataservices.ldapaccess.LdapDataAccessTest.cleanTest(LdapDataAccessTest.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: javax.naming.InvalidNameException: Invalid name: "ou=User/Group/Name"
at javax.naming.ldap.Rfc2253Parser.parseAttrType(Rfc2253Parser.java:155)
at javax.naming.ldap.Rfc2253Parser.doParse(Rfc2253Parser.java:108)
at javax.naming.ldap.Rfc2253Parser.parseDn(Rfc2253Parser.java:70)
at javax.naming.ldap.LdapName.parse(LdapName.java:785)
at javax.naming.ldap.LdapName.<init>(LdapName.java:123)
at org.springframework.ldap.support.LdapUtils.newLdapName(LdapUtils.java:414)
... 37 more
Now if I just do a normal unbind in the test it self on just the usergroup. There is no real problem.. But it is actually a problem. Because it seems Spring uses for recursive deletes the JDNI patern (thats stricter then what LDAP allows) and for normal unbinds. It works perfectly.
Now I really want to make my recursive work out of the box. I tried to delete the groups with the following code:
In the OrganisationDoa:
public void unbind(LdapOrganisation organisation, boolean recursive) {
if(organisation != null) {
UserGroupDao ugu = new UserGroupDao(ldapTemplate);
ugu.delete(organisation);
DirContextAdapter context = new DirContextAdapter(buildDn(organisation));
mapToContext(organisation, context);
ldapTemplate.unbind(context.getDn(), recursive);
}
}
And in the UserGroupDao:
public void delete(LdapOrganisation ldapOrganisation, String ldapUserGroup) {
ldapTemplate.unbind(buildDn(ldapOrganisation.getOrganisationShortname(), ldapUserGroup));
}
public void delete(LdapOrganisation ldapOrganisation) {
for (LdapUserGroup userGroup : ldapOrganisation.getUserGroups()) {
delete(ldapOrganisation,userGroup.getGroupName());
}
}
But this seems to not work, seeing i still get the same stack trace (so trying to do it in the same tread seems not to work).
I have been reading up on all these RFC specs and the seem quite old. And LDAP seems to allow it its just that because Spring seems to use JDNI for the recursive part that I get this problem. And doing a pre clean up on parts that you expect to be corrupted seems not to work as well. So I would love to hear some suggestions/ideas how to fix this.