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

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