0
votes

UPDATE: Some context on the problem below. My goal is to handle requests for users where they supply a Kafka topic with each request. I use Message Hub deployed on Bluemix as Kafka provider. The requests will pass the broker URL, topic name, username, password and API key. Message Hub on Bluemix requires JAAS authentication and provides a login module with different LoginModule implementations. Some are based on CallbackHandlers, others on CredentialProviders.

I picked the one implemented in com.ibm.messagehub.login.MultiUserLoginModule. With that module I should only have to supply a custom credential provider like:

KafkaClient {
com.ibm.messagehub.login.MultiUserLoginModule required
credentialProvider="myApp.CustomCredentialProvider";
};

The challenges are in the class loader and how the CustomCredentialProvider can get the username/password from the request passed to the MultiUserLoginModule at runtime. What configuration do I have to use to get that working?

DETAILS: I have a web application running in WebSphere Liberty 8.5.5 and want to authenticate with a third-party service. That third-party service implements a JAAS LoginModule with a CredentialProvider. My web app extends the CredentialProvider with a CustomCredentialProvider to pass credentials.

What I don't understand is how the class loading is supposed to work. My server.xml defines:

The web application

 <webApplication id="streaming-service" location="streaming-service.war" name="streaming-service"/>

The third-party login module

<jaasLoginModule className="com.ibm.messagehub.login.MultiUserLoginModule" controlFlag="REQUIRED" id="KafkaClient" libraryRef="messageHubLoginLib">
<options credentialProvider="myApp.CustomCredentialProvider" serviceName="kafka"/>
</jaasLoginModule>

The library that implements the third-party login module

   <library id="messageHubLoginLib">
    <fileset dir="${server.output.dir}" includes="messagehub.login-1.0.0.jar"/>
</library>

The login context

 <jaasLoginContextEntry id="KafkaClient" loginModuleRef="KafkaClient" name="KafkaClient"/>

The result of the above configuration is a ClassNotFoundException for my CustomCredentialProvider:

Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: myApp.CustomCredentialProvider
at com.ibm.messagehub.login.MultiUserLoginModule$MultiUserCallbackHandler.<clinit>(MultiUserLoginModule.java:80)

How do I have to change my configuration for the third-party JAAS login module to find myApp.CustomCredentialProvider implemented in my streaming-service web app?


Note: I already tried to generate a streaming-service.jar and add it directly to the messageHubLoginLib. That resolves the ClassNotFoundException but the CustomCredentialProvider class is loaded completely outside the context of my running web application and still gives me no access my credentials.

3

3 Answers

3
votes

You were nearly there with the separate streaming-service.jar. Here are all the steps that are needed.

  1. Identify the classes (from your app) that need to be visible to the login module.
  2. Put all those classes into your messageHubLoginLib (e.g. in a separate streaming-service.jar)
  3. DELETE those classes from your app.
  4. Configure the app with a class loader child element that references the login module library using a commonLibraryRef attribute:

<webApplication id="streaming-service" location="streaming-service.war" name="streaming-service">
    <classloader commonLibraryRef="messageHubLoginLib" />
</webApplication>
0
votes

Generate a streaming-service.jar and add it directly to the messageHubLoginLib should be the right way to do. In this case, you have a jar file that is share-able between your JAAS login module and Web App.

However, you said "CustomCredentialProvider class is loaded completely outside the context of my running web application and still gives me no access my credentials". It sounds like you trying to store the credential in the CustomCredentialProvider class for uses between the login module and web app.

The CustomCredentialProvider class should be independent between the login module and web app. When request come in and try to access the web app, the server trigger the login module for authentication. If it passed, the access to the web app will be successfully.

I don't see you posted. May be you are missing the following configuration?

<jaasLoginContextEntry id="system.WEB_INBOUND" name="system.WEB_INBOUND" loginModuleRef="KafkaClient,hashtable,certificate,token" />
0
votes

Can you place the MultiUserLoginModule and CustomCredentialProvider jar file in the ${server.config.dir}/lib/global directory and change the libraryRef point to global directory in your server.xml file as following:

  <jaasLoginModule className="com.ibm.messagehub.login.MultiUserLoginModule" controlFlag="REQUIRED" id="KafkaClient" libraryRef="global">
    <options credentialProvider="myApp.CustomCredentialProvider" serviceName="kafka"/>
    </jaasLoginModule>