NullPointerException occurs when bind DN is not set at LDAP authentication

(from syabuo · GitHub)
Hi,

If bind DN is not set, a system error will occur when logging in as an LDAP authenticated user.
I checked the fess.log and found that NullPointerException occurred at line 82 of LdapManager.java.

fess.log

java.lang.NullPointerException
     at java.base/java.util.Hashtable.put(Hashtable.java:475)
     at org.codelibs.fess.ldap.LdapManager.createEnvironment(LdapManager.java:82)

The 82 line of LdapManager.java sets SECURITY_PRINCIPAL.

LdapManager.java:82

env.put(Context.SECURITY_PRINCIPAL, principal);

However, since principal is set to the input value of bind DN, NullPointerException occurs if it is not input.

I would like to omit Bind DN (SECURITY_PRINCIPAL) depending on the LDAP used.
If Bind DN is not input, SECURITY_PRINCIPAL should not be set.

Thanks

(from github.com/marevol)
Bind DN is required.
What is the full stacktrace?

(from github.com/syabuo)
Full stacktrace

java.lang.NullPointerException
	at java.base/java.util.Hashtable.put(Hashtable.java:475)
	at org.codelibs.fess.ldap.LdapManager.createEnvironment(LdapManager.java:82)
	at org.codelibs.fess.ldap.LdapManager.createAdminEnv(LdapManager.java:91)
	at org.codelibs.fess.ldap.LdapManager.validate(LdapManager.java:120)
	at org.codelibs.fess.ldap.LdapManager.login(LdapManager.java:139)
	at org.codelibs.fess.app.web.base.login.FessLoginAssist.lambda$resolveCredential$4(FessLoginAssist.java:150)
	at org.lastaflute.web.login.TypicalLoginAssist$CredentialResolver.resolve(TypicalLoginAssist.java:191)
	at org.codelibs.fess.app.web.base.login.FessLoginAssist.resolveCredential(FessLoginAssist.java:145)
	at org.lastaflute.web.login.TypicalLoginAssist.findLoginUser(TypicalLoginAssist.java:120)
	at org.lastaflute.web.login.TypicalLoginAssist.doLogin(TypicalLoginAssist.java:281)
	at org.lastaflute.web.login.TypicalLoginAssist.loginRedirect(TypicalLoginAssist.java:250)
	at org.codelibs.fess.app.web.login.LoginAction.login(LoginAction.java:55)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.lastaflute.web.ruts.GodHandableAction.invokeExecuteMethod(GodHandableAction.java:335)
	at org.lastaflute.web.ruts.GodHandableAction.actuallyExecute(GodHandableAction.java:306)
	at org.lastaflute.web.ruts.GodHandableAction.doExecute(GodHandableAction.java:146)
	at org.lastaflute.web.ruts.GodHandableAction.lambda$transactionalExecute$0(GodHandableAction.java:137)
	at org.lastaflute.db.jta.stage.JTATransactionStage.performTx(JTATransactionStage.java:102)
	at org.lastaflute.db.jta.stage.JTATransactionStage.lambda$requiresNew$1(JTATransactionStage.java:59)
	at org.lastaflute.di.tx.adapter.JTATransactionManagerAdapter.requiresNew(JTATransactionManagerAdapter.java:73)
	at org.lastaflute.db.jta.stage.JTATransactionStage.requiresNew(JTATransactionStage.java:58)
	at org.lastaflute.db.jta.stage.JTATransactionStage.selectable(JTATransactionStage.java:84)
	at org.lastaflute.web.ruts.GodHandableAction.transactionalExecute(GodHandableAction.java:136)
	at org.lastaflute.web.ruts.GodHandableAction.execute(GodHandableAction.java:117)
	at org.lastaflute.web.ruts.ActionRequestProcessor.performAction(ActionRequestProcessor.java:253)
	at org.lastaflute.web.ruts.ActionRequestProcessor.fire(ActionRequestProcessor.java:182)
	at org.lastaflute.web.ruts.ActionRequestProcessor.process(ActionRequestProcessor.java:114)
	at org.lastaflute.web.servlet.filter.RequestRoutingFilter.processAction(RequestRoutingFilter.java:266)
	at org.lastaflute.web.servlet.filter.RequestRoutingFilter.routingToAction(RequestRoutingFilter.java:218)
	at org.lastaflute.web.servlet.filter.RequestRoutingFilter.lambda$createActionFoundPathHandler$0(RequestRoutingFilter.java:184)
	at org.lastaflute.web.path.ActionPathResolver.executeHandlerIfFound(ActionPathResolver.java:342)
	at org.lastaflute.web.path.ActionPathResolver.mappingActionPath(ActionPathResolver.java:208)
	at org.lastaflute.web.path.ActionPathResolver.handleActionPath(ActionPathResolver.java:113)
	at org.lastaflute.web.servlet.filter.RequestRoutingFilter.doFilter(RequestRoutingFilter.java:118)
	at org.lastaflute.web.servlet.filter.LastaToActionFilter.viaEmbeddedFilter(LastaToActionFilter.java:153)
	at org.lastaflute.web.servlet.filter.LastaToActionFilter.viaInsideHookDeque(LastaToActionFilter.java:144)
	at org.lastaflute.web.servlet.filter.LastaToActionFilter.viaInsideHook(LastaToActionFilter.java:128)
	at org.lastaflute.web.servlet.filter.LastaToActionFilter.doFilter(LastaToActionFilter.java:120)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.toNextChain(LastaShowbaseFilter.java:171)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.lambda$viaEmbeddedFilter$3(LastaShowbaseFilter.java:150)
	at org.lastaflute.web.servlet.filter.RequestLoggingFilter.actuallyFilter(RequestLoggingFilter.java:237)
	at org.lastaflute.web.servlet.filter.RequestLoggingFilter.doFilter(RequestLoggingFilter.java:209)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.viaEmbeddedFilter(LastaShowbaseFilter.java:148)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.viaOutsideHookDeque(LastaShowbaseFilter.java:139)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.viaOutsideHook(LastaShowbaseFilter.java:123)
	at org.lastaflute.web.servlet.filter.LastaShowbaseFilter.doFilter(LastaShowbaseFilter.java:115)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.codelibs.fess.filter.WebApiFilter.doFilter(WebApiFilter.java:51)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.codelibs.fess.filter.CorsFilter.doFilter(CorsFilter.java:86)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.lastaflute.web.servlet.filter.LastaPrepareFilter.toNextFilter(LastaPrepareFilter.java:280)
	at org.lastaflute.web.servlet.filter.LastaPrepareFilter.viaHotdeploy(LastaPrepareFilter.java:243)
	at org.lastaflute.web.servlet.filter.LastaPrepareFilter.viaLastaDiContext(LastaPrepareFilter.java:230)
	at org.lastaflute.web.servlet.filter.LastaPrepareFilter.doFilter(LastaPrepareFilter.java:203)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.codelibs.fess.filter.EncodingFilter.doFilter(EncodingFilter.java:119)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.base/java.lang.Thread.run(Thread.java:834)

(from github.com/marevol)
Thank you for the info!
For Bind DN, the reason comes from https://github.com/codelibs/fess/issues/741#issuecomment-252801081.

(from github.com/syabuo)
I understand why this requires BindDN.

However, the LDAP I want to connect with does not need BindDN.
In that case what to do?

(from github.com/marevol)
Added an option to skip the validation in #2185.

(from github.com/syabuo)
Thank you for your response!