Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] ClassLoader issues with custom LoginModule

Thanks for the input Jan. You are totally correct, I was missing the Neo4j jar file in the server class path. I suspect that would have been the next problem I ran in to once I got the login module so it was using the server class loader.  I updated the instructions in the repo to reflect your comments.  Thank you very much and sorry for the gaps there. I am the only person, to my knowledge, who has attempted to use this so the docs were a little lacking.

I made sure the Neo4j driver was in the server class path. I did this by adding the jar file to the JETTY_BASE/lib/ext directory;

find lib/*

lib/ext

lib/ext/postgresql-42.2.18.jar

lib/ext/neo4j-java-driver-4.4.12.jar

lib/neo4j_login_module-1.0.jar

lib/reload_sslkey_module-1.3.jar


However, I still see the same problem I had before. The trick is I am successfully connecting to the Neo4j database and authenticating the user.  But after this is completed, when creating the Credential, I am running in to the class loader problem.

java.lang.NoClassDefFoundError: org/eclipse/jetty/util/security/Credential

Before adding the neo4j driver to the server class path, I suspect I was finding the Neo4j classes because my login module is being loaded in the context of my webapp for some reason. The webapp class loader had the Neo4j driver. If I could get my login module to run in the server class loader context, then  I am sure I would have seen the problem you identified.

Is there anything I can do to get my login module to run in the context of the server class loader? 

I am not familiar with the demo JAAS webapp, I might look in to that and see if I can learn something there. 

Scott


On Tuesday, January 23, 2024, 11:25:50 PM PST, Jan Bartel <janb@xxxxxxxxxxx> wrote:


Scott,

I followed the instructions on your repo. However, instead of copying a .ini file into start.d, I just let jetty do it with:

java -jar ../jetty-home/start.jar --add-module=neo4j-authentication

When I run the jetty demo jaas webapp using your module and hit the authentication form, I get:

java.lang.NoClassDefFoundError: org/neo4j/driver/AuthTokens
	at com.bb.neo4j_login_module.Neo4jLoginModule.getUser(Neo4jLoginModule.java:276)
	at com.bb.neo4j_login_module.Neo4jLoginModule.login(Neo4jLoginModule.java:133)
	at java.base/javax.security.auth.login.LoginContext.invoke(LoginContext.java:755)
	at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:679)
	at java.base/javax.security.auth.login.LoginContext$4.run(LoginContext.java:677)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
	at java.base/javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:677)
	at java.base/javax.security.auth.login.LoginContext.login(LoginContext.java:587)
	at org.eclipse.jetty.jaas.JAASLoginService.login(JAASLoginService.java:214)
	at org.eclipse.jetty.security.authentication.LoginAuthenticator.login(LoginAuthenticator.java:62)
	at org.eclipse.jetty.security.authentication.FormAuthenticator.login(FormAuthenticator.java:173)
	at org.eclipse.jetty.security.authentication.FormAuthenticator.validateRequest(FormAuthenticator.java:262)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:528)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1580)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1381)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:484)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1553)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1303)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:192)
	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:51)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:301)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
	at org.eclipse.jetty.server.Server.handle(Server.java:563)
	at org.eclipse.jetty.server.HttpChannel$RequestDispatchable.dispatch(HttpChannel.java:1598)
	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:753)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:501)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:287)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:314)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
	at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:421)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:390)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:277)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:199)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:411)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:969)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1194)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1149)
	at java.base/java.lang.Thread.run(Thread.java:1589)
Caused by: java.lang.ClassNotFoundException: org.neo4j.driver.AuthTokens
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

That's not much of a surprise, as your neo4j login module doesn't put the neo4j classes onto the _server_ classpath. Note that they cannot be inside the webapp, as the login module is being invoked by the server path, and cannot reference classes that exist inside your webapp.

I think if you make a neo4j.mod which puts all of the necessary neo4j jars onto the server classpath, then make your neo4j-authentication.mod depend on it, then you should be ok.

cheers
Jan

On Wed, 24 Jan 2024 at 15:11, scottastanley--- via jetty-users <jetty-users@xxxxxxxxxxx> wrote:
I have written a custom LoginModule to authenticate users using nodes in a Neo4J graph database. Kind of like the functionality in the provided org.eclipse.jetty.jaas.spi.JDBCLoginModule. Basically, provide the node type and attributes in the node for the username and password and we can authenticate against the graph database. As part of this, I am using the following three classes from the Jetty distribution, 

import org.eclipse.jetty.jaas.JAASRole;

import org.eclipse.jetty.security.UserPrincipal;

import org.eclipse.jetty.util.security.Credential;

I chose to use these three classes, to simplify the process. No need to re-invent the wheel with these since they existed already and the JDBCLoginModule used them.  Probably the most critical I wanted to use was Credential since it provides the password hashing and verification logic. I saw no reason to create my own version of this since what I created would pretty much be exactly the logic from this. 

I am working with Jetty 11.0.7 and I have the whole thing working fine running under eclipse, but when I try and use it in a standalone jetty instance I am getting class loader problems. When I try and create a credential using,

Credential.getCredential(neo4jCredential);

I am getting this;

java.lang.NoClassDefFoundError: org/eclipse/jetty/util/security/Credential

When I debug the problem, what I am finding is that the class loader context for the JDBCLoginModule is not the same as for my custom login module. When in the initialize() method of the login modules I see this;

Using the JDBCLoginModule

this.getClass()

class org.eclipse.jetty.jaas.spi.JDBCLoginModule


this.getClass().getClassLoader()

startJarLoader@2d3379b4



Using the Neo4jLoginModule
this.getClass()

class com.bb.neo4j_login_module.Neo4jLoginModule


this.getClass().getClassLoader()

WebAppClassLoader{Fermenation}@6bc28a83

My login module is deployed just like any other jetty module, isolated from my webapp.  These files are included in my JETTY_BASE directory;

etc/neo4j-authentication.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">

<Configure id="Server" class="org.eclipse.jetty.server.Server">

    <Call name="addBean">

        <Arg>

            <New class="org.eclipse.jetty.jaas.JAASLoginService">

                <Set name="name">beercalc.realm</Set>

                <Set name="LoginModuleName">beercalc.login.module</Set>

            </New>

        </Arg>

    </Call>

</Configure>

lib/neo4j_login_module-1.0.jar
Jar file containing the classes for the login module. Code is in a public repo here; GitHub - scottastanley/neo4j_login_module, if there is anything in the implementation that should matter.


modules/neo4j-authentication.mod

[description]

Configures the Neo4J JAAS login module.


[depend]

server

jaas


[lib]

lib/neo4j_login_module-1.0.jar


[xml]

etc/neo4j-authentication.xml


[ini-template]

# --------------------------------------- 

# Module: neo4j-authentication

# Enables the JAAS Login service for authentication against Neo4J. 

# --------------------------------------- 

--module=neo4j-authentication



start.d/neo4j-authentication.ini

# --------------------------------------- 

# Module: neo4j-authentication

# Enables the JAAS Login service for authentication against Neo4J. 

# --------------------------------------- 

--module=neo4j-authentication

I am aware that I am not supposed to be able to use server classes in a webapp. So, I am sure this is why the Credential class is not found. But I can not figure out why my login module is being loaded in the webapp context. I had assumed it would operate under the same class loaded as the JDBCLoginModule. I know that I should be able to change the filtering of server classes by the class loader in the webapp, although the only concrete example I have found is doing it for Jetty 8 and this has changed in Jetty 11. So, have not figured that out yet. Although I would rather figure out why the module is using the webapp classloader so I do not need to set up customer, more permissive class loader configuration.

The really funny thing is I have been using the static method Credential.MD5.digest(password) in my actual web application for a long time in the logic allowing users to change their password. Not sure how or why this ever worked, but I know it did in Jetty 8. I will admit, I just tested tonight and this no longer works. Must have gotten broken when I upgraded to Jetty 11 and I never realized.

Is there any way to get my module to utilize the startJarLoader instead of the one in the webapp? I would really like to get this figured out. I may need to reimplement the whole Credential logic anyway since I can't use the method to digest passwords anymore. That would be a shame, but I do need the symmetric digest/validate logic available.

I really appreciate any insight anyone has on why the module is using the webapp class loader.  Would really like to understand this.  Also, if anyone has any suggestions on how to solve this problem besides re-implementing/duplicating the credential logic I'd appreciate it.

Scott


 
_______________________________________________
jetty-users mailing list
jetty-users@xxxxxxxxxxx
To unsubscribe from this list, visit https://www.eclipse.org/mailman/listinfo/jetty-users


--
Jan Bartel <janb@xxxxxxxxxxx>
www.webtide.com
Expert assistance from the creators of Jetty and CometD


Back to the top