I am writing test cases and in the actual service code during the add operation a subcontext is created from the context to verify the newly created user.
I create a context
contextSource.getReadWriteContext();
I have Spring setting the contextSources and then actual code retrieves the context from the contextSource.
But
When the code attempts to create a subContext an exception is thrown:
[LDAP: error code 32 - Unable to add entry 'uid=123456' because its parent entry 'null' does not exist in the server.]
In the debugger I see the context is defaultContext.
How can I get the subcontext? Can I not get a subcontext with a default context? I am running in memory - does that have something to do with it? Maybe the new user was not added or recognized as such inmemory?
@BeforeClasspublicstaticvoidsetup(){try{loadProperties();LOG.info("inMemoryDB="+inMemoryDB);LOG.info("inMemoryLDAP="+inMemoryLDAP);createDatabases();createLdapServers();createService();}catch(Exceptione){LOG.error("Exceptionoccurredduringtestsetup:", e); }}private static ContextSource cs; protected static InMemoryDirectoryServer inMemoryDirSvr;createLdapServers(): LDAPServer ldapServer = new LDAPServer( inMemoryServer, inMemoryLdapPort, ldapUserDn, ldapPwd, inMemoryListenerName, dataFile, schemaFile, strSearchDN); cs= createContextSource(ldapServer);//class variable inMemoryDirSvr = embedUnboundId(ldapServer);private static ContextSource createContextSource(LDAPServer ldapServer) throws Exception{ LdapContextSource cs = new LdapContextSource(); cs.setUrl(ldapServer.getLongUrl()); cs.setUserDn(ldapServer.getUserDn()); cs.setPassword(ldapServer.getLdapPwd()); /** * afterPropertiesSet(): * Checks that all necessary data is set and that there is no compatibility * issues, after which the instance is initialized. Note that you need to * call this method explicitly after setting all desired properties if using * the class outside of a Spring Context. */ cs.afterPropertiesSet(); return cs;}private static InMemoryDirectoryServer embedUnboundId(LDAPServer ldapServer)throws Exception{ InMemoryDirectoryServerConfig config = configureInMemLdapServer(ldapServer); // Create the directory server instance, populate it with data from the // "test-data.ldif" file, and start listening for client connections. InMemoryDirectoryServer dirSvr; dirSvr = new InMemoryDirectoryServer(config); LOG.info("schema:"+ dirSvr.getSchema().toString()); URL fileUrl = BaseTestSetup.class.getResource(ldapServer.getDataFileName()); String path = fileUrl.getPath(); int status = dirSvr.importFromLDIF(true, path); dirSvr.startListening(); return dirSvr;}private static InMemoryDirectoryServerConfig configureInMemLdapServer(LDAPServer ldapServer)throws Exception{ // Create the configuration to use for the server. InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig( "dc=company,dc=com", "o=company.com"); config.addAdditionalBindCredentials(ldapServer.getUserDn(), ldapServer.getLdapPwd()); URL fileUrl = BaseTestSetup.class.getResource(ldapServer.getSchemaFileName()); File file = new File(fileUrl.toURI()); Schema schema = Schema.getSchema(file); LOG.info("schema:"+schema.toString());config.setSchema(schema);InMemoryListenerConfiglistenerConfig=newInMemoryListenerConfig(ldapServer.getListenerName(),null,ldapServer.getPort(),null,null,null);config.setListenerConfigs(listenerConfig);/* https://sourceforge.net/p/ldap-sdk/discussion/1001257/thread/0c3a2bec/ The actual Directory Server is not LDAPv3-compliant. The setEnforceSingleStructuralObjectClass and methods setEnforceAttributeSyntaxCompliance methods can be used to allow the in-memory directory server to behave more like some of the less-compliant servers. Without this the data will fail while loading and validating against the schema: ... */config.setEnforceSingleStructuralObjectClass(false);config.setEnforceAttributeSyntaxCompliance(false);/* setGenerateOperationalAttributes to false else on modify got error: LDAP: error code 65 - Unable to modify...would have violated the provided schema: */config.setGenerateOperationalAttributes(false);returnconfig;}
Any ideas why I get an error creating the subcontext?
Thanks
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I was thinking the same direction, but then I saw:
URL fileUrl = BaseTestSetup.class.getResource(ldapServer.getDataFileName());
String path = fileUrl.getPath();
int status = dirSvr.importFromLDIF(true, path);
So it looks like a rootDn is being loaded into the server.
What are the actual values for 'ldapUserDn' and 'strSearchDN'? Is ldapUserDn a full bind (eg uid=username,dc=company,cd=com). Are you maybe mixing baseDn with strSearchDn?
Last edit: Pali Haneul 2014-05-14
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Spring configuration:
I used the minimal settings where the same file could be used in production against live ldap servers as well as testing utilizing UnboundID
The baseDN I believe I am setting here:
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(/ldapServer.getLogOnBaseDNs()/ "dc=companyName,dc=com", "o=companyName.com");
ldapUserDn is:
cn=pgmuser_globalsearch,ou=appid,o=company.com
strSearchDn is:
"ou=NonEmployees, ou=People, o=company.com"
The following were added because I was importing an LDAP data file from an LDAP server and it appears to not follow the expected standards...so I have to set the flags to make unboundId more lenient:
On Modify had to add this - also because of the server data structure not being compliant:
config.setGenerateOperationalAttributes(false);
If DirContext ctx =contextSource.getReadWriteContext() does not create a context with a proper base dn - what do I need to do / what am I doing wrong? The current tests have been doing search/lookup/etc but I have not attempted getting a subcontext before... used to verify user just added works.
ctxNew = ctx.createSubcontext(strDN, attrs);
strDn="uid=123abc"
ctx in the debugger has:
myProps (Hashtable size 7)
gotDefault=true
defaultInitCtx with many values some that may help:
currentDn=""
currentParsedDn=""
parentIsLdapCtx=false
_contextType=2
bindCtls=null
hasLdapsScheme=false
So it looks like maybe the context does not have the proper baseDn....
Any ideas why/how to fix?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Unable to perform the search because base entry 'ou=NonEmployees, ou=People, o=companyName.com,dc=companyName,dc=com,o=companyName.com'
does not exist in the server.];
remaining name 'ou=NonEmployees, ou=People, o=companyName.com'
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Update: calls were occasionally being made to determine the ldap query string utilizing javax.naming.directory.SearchResult.getNameInNamespace(). When this method was called the baseDn was present twice.
To get the subcontext from the Spring context a baseDn needed to be defined in the Spring configuration file. Defining the baseDn in the Spring config, caused ", o=companyName.com" aka the baseDn to be appended to the strDn used to search the ldap server. The LDAPConstants strDn values were fixed to not include the baseDn - since it would be appended to the string behind the scenes. However portions of the code do not use LDAPCConstants, rather they use this method to get the full ldap search path...and then the baseDn is appended again causing an error in certain methods. An example exception message:
06/13/2014 16:12:26 [DEBUG] org.springframework.ldap.core.support.AbstractContextSource
Got Ldap context on server 'ldap://localhost:port123/o=companyName.com'
javax.naming.NameNotFoundException: [LDAP: error code 32 - Unable to modify entry
'uid=someName,ou=NonEmployees,ou=People,o=companyName.com,o=companyName.com'
because it does not exist in the server.];
remaining name 'uid=someName,ou=NonEmployees,ou=People,o=companyName.com'
I just created a local service method for a quick fix.
I am writing test cases and in the actual service code during the add operation a subcontext is created from the context to verify the newly created user.
I create a context
contextSource.getReadWriteContext();
I have Spring setting the contextSources and then actual code retrieves the context from the contextSource.
But
When the code attempts to create a subContext an exception is thrown:
[LDAP: error code 32 - Unable to add entry 'uid=123456' because its parent entry 'null' does not exist in the server.]
In the debugger I see the context is defaultContext.
How can I get the subcontext? Can I not get a subcontext with a default context? I am running in memory - does that have something to do with it? Maybe the new user was not added or recognized as such inmemory?
Some code:
my service config xml file:
The setup of unbounded:
Any ideas why I get an error creating the subcontext?
Thanks
It looks like that you are missing a base DN when trying to create sub context. Shouldn't you provide a base in the Spring configuration?
E.g.
<property name="base" value="dc=company,dc=com" />
I was thinking the same direction, but then I saw:
So it looks like a rootDn is being loaded into the server.
What are the actual values for 'ldapUserDn' and 'strSearchDN'? Is ldapUserDn a full bind (eg uid=username,dc=company,cd=com). Are you maybe mixing baseDn with strSearchDn?
Last edit: Pali Haneul 2014-05-14
I'm also a bit thrown off by this:
Earlier today I also started InMemoryDirectoryServer from scratch but I haven't touched any of those settings.
I think that the InMemoryDirectoryServer has all the entries, but I don't think that the
creates a context with the proper base DN.
Thanks for looking into it.
Spring configuration:
I used the minimal settings where the same file could be used in production against live ldap servers as well as testing utilizing UnboundID
The baseDN I believe I am setting here:
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(/ldapServer.getLogOnBaseDNs()/ "dc=companyName,dc=com", "o=companyName.com");
Then sign on credentials here:
config.addAdditionalBindCredentials(ldapServer.getUserDn(), ldapServer.getLdapPwd());
ldapUserDn is:
cn=pgmuser_globalsearch,ou=appid,o=company.com
strSearchDn is:
"ou=NonEmployees, ou=People, o=company.com"
The following were added because I was importing an LDAP data file from an LDAP server and it appears to not follow the expected standards...so I have to set the flags to make unboundId more lenient:
config.setEnforceSingleStructuralObjectClass(false);
config.setEnforceAttributeSyntaxCompliance(false);
On Modify had to add this - also because of the server data structure not being compliant:
config.setGenerateOperationalAttributes(false);
If DirContext ctx =contextSource.getReadWriteContext() does not create a context with a proper base dn - what do I need to do / what am I doing wrong? The current tests have been doing search/lookup/etc but I have not attempted getting a subcontext before... used to verify user just added works.
ctxNew = ctx.createSubcontext(strDN, attrs);
strDn="uid=123abc"
ctx in the debugger has:
myProps (Hashtable size 7)
gotDefault=true
defaultInitCtx with many values some that may help:
currentDn=""
currentParsedDn=""
parentIsLdapCtx=false
_contextType=2
bindCtls=null
hasLdapsScheme=false
So it looks like maybe the context does not have the proper baseDn....
Any ideas why/how to fix?
Ok it looks like the baseDn is set on the inmemory server but not on the contextsource.
So it looks like I need to probably do contextSource.setBase("dc=companyName,dc=com,o=companyName.com") or some other value?...
However once I put any value in setBase other areas start throwing exceptions like:
javax.naming.NameNotFoundException: [LDAP: error code 32 -
Unable to perform the search because base entry 'ou=NonEmployees, ou=People, o=companyName.com,dc=companyName,dc=com,o=companyName.com'
does not exist in the server.];
remaining name 'ou=NonEmployees, ou=People, o=companyName.com'
I am guessing that your base should be either dc=companyName,dc=com or o=companyName.com but not both.
Since you confirmed that the base DN is properly set in the in-memory directory server, I would check out the Spring LDAP samples at https://github.com/spring-projects/spring-ldap/tree/master/samples
Update: calls were occasionally being made to determine the ldap query string utilizing javax.naming.directory.SearchResult.getNameInNamespace(). When this method was called the baseDn was present twice.
To get the subcontext from the Spring context a baseDn needed to be defined in the Spring configuration file. Defining the baseDn in the Spring config, caused ", o=companyName.com" aka the baseDn to be appended to the strDn used to search the ldap server. The LDAPConstants strDn values were fixed to not include the baseDn - since it would be appended to the string behind the scenes. However portions of the code do not use LDAPCConstants, rather they use this method to get the full ldap search path...and then the baseDn is appended again causing an error in certain methods. An example exception message:
06/13/2014 16:12:26 [DEBUG] org.springframework.ldap.core.support.AbstractContextSource
Got Ldap context on server 'ldap://localhost:port123/o=companyName.com'
javax.naming.NameNotFoundException:
[LDAP: error code 32 - Unable to modify entry
'uid=someName,ou=NonEmployees,ou=People,o=companyName.com,o=companyName.com'
because it does not exist in the server.];
remaining name 'uid=someName,ou=NonEmployees,ou=People,o=companyName.com'
I just created a local service method for a quick fix.
/ kludge /
public String getNameInNamespace(SearchResult userResult{
String fullName = userResult.getNameInNamespace();
int endIndex = fullName.lastIndexOf(",");
String newValue = fullName.substring(0, endIndex);
return newValue;
}