eclipse-ee4j / glassfish

Eclipse GlassFish
https://eclipse-ee4j.github.io/glassfish/
387 stars 144 forks source link

Problem with LDAP in Glassfish v3 #11997

Closed glassfishrobot closed 13 years ago

glassfishrobot commented 14 years ago

I have a problem using LDAP under Glassfish v3 (open source). Apparently, when our LDAP client tries to search for the user information an exception is thrown. However, the exact same code works well under Tomcat. To illustrate the fact that this is not a problem in the LDAP client (or at least, doesn't seem to be), I created a simple war with a JSP file that calls the same method the LDAP client calls. The JSP (which consist only of JRE code) runs well under Tomcat, but fails in Glassfish. The exception that is thrown is:

javax.naming.InvalidNameException: ldap:: [LDAP: error code 34 - Invalid DN]; remaining name 'ldap://16.55.249.190:63379/ou%3Dscranton%2Cdc%3Ddunder%2Cdc% 3DMifflin' at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2979) at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2794) at com.sun.jndi.ldap.LdapCtx.c_lookup(LdapCtx.java:1011) at com.sun.jndi.toolkit.ctx.ComponentContext.c_resolveIntermediate_nns (ComponentContext.java:152) at com.sun.jndi.toolkit.ctx.AtomicContext.c_resolveIntermediate_nns (AtomicContext.java:342) at com.sun.jndi.toolkit.ctx.ComponentContext.p_resolveIntermediate (ComponentContext.java:423) at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search (ComponentDirContext.java:360) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search (PartialCompositeDirContext.java:338) at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search (PartialCompositeDirContext.java:321) at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:248) at org.apache.jsp.test_jsp._jspService(test_jsp.java from :83) at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:109) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) at org.apache.jasper.servlet.JspServletWrapper.service (JspServletWrapper.java:406) at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:483) at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:373) at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523) at org.apache.catalina.core.StandardWrapperValve.invoke (StandardWrapperValve.java:279) at org.apache.catalina.core.StandardContextValve.invoke (StandardContextValve.java:188) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke (PESessionLockingStandardPipeline.java:85) at org.apache.catalina.core.StandardHostValve.invoke (StandardHostValve.java:185) at org.apache.catalina.connector.CoyoteAdapter.doService (CoyoteAdapter.java:332) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:233) at com.sun.enterprise.v3.services.impl.ContainerMapper.service (ContainerMapper.java:165) at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791) at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693) at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954) at com.sun.grizzly.http.DefaultProtocolFilter.execute (DefaultProtocolFilter.java:170) at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter (DefaultProtocolChain.java:135) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102) at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88) at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76) at com.sun.grizzly.ProtocolChainContextTask.doCall (ProtocolChainContextTask.java:53) at com.sun.grizzly.SelectionKeyContextTask.call (SelectionKeyContextTask.java:57) at com.sun.grizzly.ContextTask.run(ContextTask.java:69) at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork (AbstractThreadPool.java:330) at com.sun.grizzly.util.AbstractThreadPool$Worker.run (AbstractThreadPool.java:309) at java.lang.Thread.run(Thread.java:619)

(the war is attached)

I did some digging and found out why Glassfish is behaving differently than Tomcat.

As you can see in the stack trace, the JSP calls the method:

InitialDirContext.search(String name, String filter, SearchControls cons) which calls: InitialDirContext.getURLOrDefaultInitDirCtx(String name) which calls: InitialContext.getURLOrDefaultInitCtx(String name) which calls: NamingManager.hasInitialContextFactoryBuilder

Here lies the difference:

Under Tomcat NamingManager.hasInitialContextFactoryBuilder returns false. Consequently, the following code is run:

String scheme = getURLScheme(name); if (scheme != null) { Context ctx = NamingManager.getURLContext(scheme, myProps); if (ctx != null) { return ctx; } }

A new context is created as an object of the class: ldapURLContext. From here on the code works well and the user is successfully authenticated (in our LDAP client)

Under Glassfish, however, NamingManager.hasInitialContextFactoryBuilder returns true (because it has an initial context factory builder â€" GlassFishNamingBuilder). Consequently, IniticalContext.getDefaultInitCtx() is called, which returns an object of the class LdapCtx. Then (as you can see in the stack trace), instead of ldapURLContext an object of the class PartialCompositeDirContext is used to process the request. For some reason, this flow fails with the exception above.

Why does this happen? Is this a bug in Glassfish, or is there a problem with the method call? Is there a workaround?

Environment

Operating System: All Platform: All

Affected Versions

[V3]

glassfishrobot commented 6 years ago
glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Created an attachment (id=4376) war that reproduces the problem

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: I would like to stress the urgency of this issue. We are using Glassfish for the first time. If this is not solved we will not be able to use Glassfish at all. If we don't find a solution soon we will have to switch to something else

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Sorry to be a nag, but this is very very urgent and I am not getting any response. So I will elaborate on the urgency here. I work at HP. We are working on a new product. We thought of using Glassfish v3 because it supports JEE6 and EJB 3.1. We also use SAP's Business Objects. Business Objects is essential to our new product. Unfortunately, Business Objects' LDAP authentication does not work in Glassfish. However, as I mentioned in the bug report, the exact same code works well in Tomcat. As mentioned in the bug report, I did some digging and found the problem. The reason Glassfish and Tomcat behave differently is because Glassfish uses an initial context factory builder (GlassFishNamingBuilder) and Tomcat does not. I don't know if this is a bug in Glassfish or a problem in the way Business Objects does the LDAP search (but I did manage to reproduce it using a simple war that only uses JRE code which works well in Tomcat but fails in Glassfish). Either way, this is a problem we can't ignore. Unless there is a fix or a workaround we will have to drop Glassfish and look for another solution. This is not a decision we will be making lightly. We have already invested several months in Glassfish. We will have to do it all over again with whichever other solution we will choose. Unfortunately, we do not have a choice. Please let me know if this is indeed a bug (and if you are going to fix it) or if there is a workaround to this problem

glassfishrobot commented 14 years ago

@glassfishrobot Commented kumara said: Adding comment from issues mailing list –

We are looking into the issue. Yes, we indeed use a Initial context builder. We will respond once we understand whats going on OR once we have a work around.

glassfishrobot commented 14 years ago

@glassfishrobot Commented ss141213 said: I think I know what's going on here. It is both an application bug as well as bug in GlassFish naming module. LdapContext is used instead of ldapURLContext because the code has passed "java.naming.factory.initial" as "com.sun.jndi.ldap.LdapCtxFactory"). When this is present, the builder is going to create an LdapCtxFactory for reasons mentioned below: InitialDirContext.search(String) -> InitialDirContext.getURLOrDefaultInitDirCtx(String) -> InitialContext.getURLOrDefaultInitCtx(String) { -> getDefaultInitCtx() // this is because builder is set -> NamingManager.getInitialContext(HashTable) -> builder.createInitialContextFactory(HashTable) -> Instantiate com.sun.jndi.ldap.LdapCtxFactory as that's passed as the initial context factory class name.

So, you should not set java.naming.factory.initial in the environment variable. If you do so, you shall get following exception:

javax.naming.NotContextException: Not an instance of DirContext at javax.naming.directory.InitialDirContext.getURLOrDefaultInitDirCtx(InitialDirContext.java:92) at ...

This is a GlassFish bug. Let me explore further.

glassfishrobot commented 14 years ago

@glassfishrobot Commented mk111283 said: Meanwhile, as a work around try this:

String filter = "(uid=" + user + ")";

String encodedRoot = URLEncoder.encode(root,"UTF-8");

String url = encodedRoot;

String[] attrs = new String[]

{"objectclass"}

;

SearchControls searchControls = new SearchControls(2, -8251450396950659072L, 0, attrs, false, false);

context.search(url, filter, searchControls);

glassfishrobot commented 14 years ago

@glassfishrobot Commented mk111283 said: If it helps, here is what I tried with OpenDS

try {

Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:1389"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager"); env.put(Context.SECURITY_CREDENTIALS, "password"); DirContext ctx = new InitialDirContext(env); Attributes attributes = ctx.getAttributes(""); NamingEnumeration<? extends Attribute> e = attributes.getAll(); while (e.hasMore())

{ out.println(e.next() + "

"); }

String filter = "(cn=*)";

String encodedRoot = URLEncoder.encode(root,"UTF-8");

String url = "dc=example,dc=com";

String[] attrs = new String[]

{"objectclass"}

;

SearchControls searchControls = new SearchControls(2, -8251450396950659072L, 0, attrs, false, false);

NamingEnumeration e2 = ctx.search(url, filter, null); while (e2.hasMore())

{ out.println("

entry : " + e2.next() + "

"); }

out.println("SUCCESS");

} catch (Exception e)

{ out.println("FAILURE!

"); e.printStackTrace(new PrintWriter(out)); }

HTH

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Thank you very much for your help. I tried the workaround but it didn't help. I get the same exception in Glassfish, and now I get it in Tomcat as well. In addition, this kind of workaround will not solve my problem, because the LDAP code it not ours. It's a third party code. It is the LDAP implementation in SAP's Business Objects, which we use. I am also trying to understand ss141213's following comment: "So, you should not set java.naming.factory.initial in the environment variable". Is that possible? Which environment variable? How do I set it? Also, is this a good idea? Won't this change the way Glassfish works in naming in general, including JNDI and CDI? Is this safe?

Thanks, Ifat

glassfishrobot commented 14 years ago

@glassfishrobot Commented ss141213 said: Ifat,

What exactly did you change? Try just changing the following line your test.jsp:

url = root;

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Oh, you mean change the line:

String url = "ldap://" + host + ":" + port + "/" + encodedRoot;

to

String url = root;

(In the previous comment you changed it to:

String url = encodedRoot;

which caused the same exception in both Glassfish and Tomcat)

Anyway, this does work. Unfortunately, it doesn't help me. I can't change the LDAP code. It is not our code. It's a third party code we use (SAP Business Objects)

glassfishrobot commented 14 years ago

@glassfishrobot Commented ss141213 said: You are getting confused between my comments and someoneelse's. I had never asked to change to url = encodedRoot.

Anyway, now that you at least know changing to url = root; works, tell us what code is in your control so that we can think what is a possible work around for you.

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Yes, you are right, it was mk111283 who suggested that.

In regards to your question, unfortunately, the answer is none. None of the code is in our control. This code is part of SAP's Business Objects. Our code uses Business Objects SDK to access the Business Objects application. Before doing anything Business Objects SDK first must authenticate the user. One of the methods for authentication is LDAP authentication. Neither the application nor the SDK is in our control. It's a third party software, which is not even an open source.

I believe the only kind of workaround we will be able to use will have to do something with configuration. Either a config file or something at runtime.

You (I checked, now it is you ) wrote: "So, you should not set java.naming.factory.initial in the environment variable". Was that meant for me? If so then:

1. Is that a valid solution? 2. Is that a safe solution? 3. Whar are the ramifications? 4. How do I do that?

Thanks, Ifat

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Hi,

Are there any news? Is there a bug fix for this issue?

Thanks, Ifat

glassfishrobot commented 14 years ago

@glassfishrobot Commented ss141213 said: Not a p1.

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Hi,

Could you please tell me what is the status of the bug? Was there any progress? Are you planning to fix it?

Thanks, Ifat

glassfishrobot commented 14 years ago

@glassfishrobot Commented kumara said: The new features for 3.1 has taken higher priority than fixing bugs but we will get back to this issue soon. Given that a workaround was provided the priority was lowered to P3. Our goal is to fix most P3 issues before the release of 3.1. For this particular issue, we need more analysis to determine whether it makes sense to fix it in GlassFish 3.1. Please stay tuned, you should have an update late September/early October.

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: OK, Thanks.

glassfishrobot commented 14 years ago

@glassfishrobot Commented ss141213 said: ms7

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Could you please explain what that means? What is the ETA of the fix?

glassfishrobot commented 14 years ago

@glassfishrobot Commented ifatgv said: Could you please explain the meaning of the target milestone change? We must know the ETA. This has a significant effect on our product

glassfishrobot commented 13 years ago

@glassfishrobot Commented jtaragin said: Are there plans to fix this bug for 3.1? I have a case that is running into the same issues.

It seems to be marked to be fixed in 3.1. Is that still the plans?

Thanks

glassfishrobot commented 13 years ago

@glassfishrobot Commented ss141213 said: Yes, it is on my list of bugs for 3.1

glassfishrobot commented 13 years ago

@glassfishrobot Commented jtaragin said: Great. Do you know which milestone you plan to get to it?

Thanks

glassfishrobot commented 13 years ago

@glassfishrobot Commented ss141213 said: I have a fix which I have sent to Mahesh for review. I need approval to check in.

How bad is its impact? (Severity) Limited

How often does it happen? Will many users see this problem? Certain users using LDAP and JNDI may see this.

How much effort is required to fix it? (Cost) Very Low

What is the risk of fixing it and how will the risk be mitigated? (Risk) Very Low.

glassfishrobot commented 13 years ago

@glassfishrobot Commented mk111283 said: Changes look OK to me.

My understanding is that in GF, we will be using the glassfish InitialContextFactoryBuilder by default unless a specific system property (com.sun.enterprise.naming.allowJndiLookupFromOSGi) is set to false

glassfishrobot commented 13 years ago

@glassfishrobot Commented ai109478 said: Approved for checkin

glassfishrobot commented 13 years ago

@glassfishrobot Commented ss141213 said: ss141213@Sahoo:~/WS/gf/v3$ svn commit -m "Issue 11997: Allow user to configure use of naming builder, which is used to enable jndi lookups from a thread with undefined tcl. To turn off the builder, which is enabled by default, one has to set com.sun.enterprise.naming.allowJndiLookupFromOSGi=false." common/glassfish-naming/ Sending common/glassfish-naming/src/main/java/com/sun/enterprise/naming/GlassFishNamingBuilder.java Transmitting file data . Committed revision 43882.

So, submitter of this bug is requested to set the aforementioned system property in their environment. In a future release, we will consider enhancing this code.

Code has been reviewed by Mahesh.

glassfishrobot commented 14 years ago

@glassfishrobot Commented File: testldap.war Attached By: ifatgv

glassfishrobot commented 14 years ago

@glassfishrobot Commented Was assigned to ss141213

glassfishrobot commented 7 years ago

@glassfishrobot Commented This issue was imported from java.net JIRA GLASSFISH-11997