Custom authProvider class not found when deploying plugin

Hello
I’m writing a custom authentification for my users and I want to do this through a plugin so I can manage versioning/deployment/update… more easily.
So I created a new plugin with one main class implementing org.jivesoftware.openfire.container.Plugin interface and another class implementing org.jivesoftware.openfire.auth.AuthProvider.

I followed this >thread< in the main class of my plugin, but when I deploy the plugin in my OF, I have the following stacktrace :

2019.04.16 11:33:38 DEBUG [pool-5-thread-1]: org.jivesoftware.openfire.container.PluginMonitor - Extracting plugin 'myplugin.openfire.plugin-openfire-plugin-assembly'...
2019.04.16 11:33:38 DEBUG [pool-5-thread-1]: org.jivesoftware.openfire.container.PluginMonitor - Successfully extracted plugin 'myplugin.openfire.plugin-openfire-plugin-assembly'.
2019.04.16 11:33:38 DEBUG [pool-34-thread-1]: org.jivesoftware.openfire.container.PluginManager - Loading plugin 'myplugin.openfire.plugin-openfire-plugin-assembly'...
2019.04.16 11:33:39 WARN  [pool-34-thread-1]: org.jivesoftware.util.SystemProperty - Class com.myplugin.openfire.plugin.Username2AuthProviderImpl was not found
java.lang.ClassNotFoundException: com.myplugin.openfire.plugin.Username2AuthProviderImpl
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_191]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_191]
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_191]
        at java.lang.Class.forName0(Native Method) ~[?:1.8.0_191]
        at java.lang.Class.forName(Class.java:264) ~[?:1.8.0_191]
        at org.jivesoftware.util.SystemProperty.lambda$static$9(SystemProperty.java:100) ~[xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.SystemProperty.getValue(SystemProperty.java:300) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.SystemProperty$1.propertySet(SystemProperty.java:195) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.PropertyEventDispatcher.dispatchEvent(PropertyEventDispatcher.java:87) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.JiveProperties.put(JiveProperties.java:302) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.JiveGlobals.setProperty(JiveGlobals.java:811) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.util.JiveGlobals.setProperty(JiveGlobals.java:793) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at com.myplugin.openfire.plugin.MyPluginMainClass.initializePlugin(MyPluginMainClass.java:27) [myplugin.openfire.plugin-1.0.jar!/:?]
        at org.jivesoftware.openfire.container.PluginManager.loadPlugin(PluginManager.java:634) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.openfire.container.PluginMonitor$MonitorTask$4.call(PluginMonitor.java:380) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at org.jivesoftware.openfire.container.PluginMonitor$MonitorTask$4.call(PluginMonitor.java:368) [xmppserver-4.4.0-SNAPSHOT.jar:4.4.0-SNAPSHOT]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_191]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_191]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_191]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_191]
2019.04.16 11:33:39 DEBUG [pool-34-thread-1]: org.jivesoftware.openfire.container.PluginManager - Initialized plugin 'myplugin.openfire.plugin-openfire-plugin-assembly'.
2019.04.16 11:33:39 INFO  [pool-34-thread-1]: org.jivesoftware.openfire.container.PluginManager - Successfully loaded plugin 'myplugin.openfire.plugin-openfire-plugin-assembly'.
2019.04.16 11:33:39 INFO  [pool-5-thread-1]: org.jivesoftware.openfire.container.PluginMonitor - Finished processing all plugins.

In my Plugin main class, my initializePlugin() is :

@Override
public void initializePlugin(PluginManager manager, File pluginDirectory) {
	Username2AuthProviderImpl myAuthProvider = new Username2AuthProviderImpl();
	JiveGlobals.setProperty("provider.auth.className", myAuthProvider.getClass().getName());
}

I believe the Openfire core classloader doesn’t find my class, so how can I achieve this ?

Openfire’s plugin API is very versatile, and can be used to do almost anything - but to add a User, Auth or Group provider, you’d better not use a plugin.

Plugins run in their own, isolated, classloader. This is done by design, but it’s also what is causing the issue that you’re experiencing.

To create an AuthProvider (or Group-, or UserProvider), it is advisable to create an ordinary library (a jar file), and add that to the Openfire ‘lib’ directory, before starting. This will make available your code on the core classpath of Openfire.

You can find some more details on http://download.igniterealtime.org/openfire/docs/latest/documentation/db-integration-guide.html

Ok, thank you for the infos. Is there any openfire library around there that I could take as an example ?

I’m unaware of any. But if you have a plugin with your code, you’re nearly there. All you need to do is to make that project not a plugin (but a simple JAR library). Then, manually, set the ‘provider.auth.className’ property to your classname, and you should have something to work with.

Indeed, I just thought of doing something like (due to some problems I had at first to make Openfire deploy my plugin because Maven generates 2 war, one “assembly” which contains all ressources, especially plugin.xml and another JAR whithout it)

I’ll try using the other JAR and adding it to the /lib dir of Openfire.

And about the ‘provider.auth.className’ property : if I add it to openfire.xml, will take it into account each time it starts ? or only at the first startup ? or never ?

Newer versions of Openfire will migrate it to the database (meaning that it will be removed from the XML file, and stored in the database). You’ll need to use appropriate XML elements though - it’s often easier to add it to the properties in the admin console directly. That has the same effect, but less chance of mistakes.

Yes for my development I can do that, but in the future we will deploy multiple instances of Openfire and for each of them we will want to add our custom library and then set our server properties accordingly.
So I need a way to do it programmatically :wink:

By the way, thank’s for your help !

Edit 17/04 for @guus
If I’m developping a JAR to put in /lib of Openfire, should I keep the parent artifact (from a maven point of view) to :

    <parent>
        <artifactId>plugins</artifactId>
        <groupId>org.igniterealtime.openfire</groupId>
        <version>4.3.0</version>
    </parent>

or shoud l use another artifactId ? I tried to use xmppserver but it’s not working.

I suggest you don’t have a parent at all. It should be as easy as defining a runtime dependency on xmppserver.

@Bpt did you find a way to change server properties programmatically?
I’ve tried to set them in openfire.xml, but I had this warning:

2020.05.22 10:20:19 org.jivesoftware.util.XMLProperties - XML Property ‘provider.user.className’ differs from what is stored in the database. Please make property changes in the database instead of the configuration file.

For *providers mechanisms we are inserting/modifiying values in the database before starting Openfire.
For other properties, the best way to modify them programmatically in my opinion is to use the REST API plugin for Openfire. (because when you modify a parameter through the REST Api, the listeners on this parameter are triggered).

It’s funny that I had it working (as a plugin) by following the suggestion of this thread Custom auth provider in a plugin - #30 by Patrick13.

But then it fails again once in a while.

I can see how that solution works, but that’s more as a result of certain timing and side-effects, rather than by design. If anything changes (in the plugin, or Openfire), then there’s a real risk of the solution imploding completely.

In the long run, you’ll benefit from not having these very specific applications being implemented as a plugin.