javaauthenticationjmsweblogic12cwildfly-26

WebLogic 12c Foreign Server fails to authenticate with WildFly 26 JMS: JMSSecurityException (Username: null)


I have a Java application running on WebLogic 12c that sends JMS messages. We're trying to configure it to send messages to a remote JMS queue on a WildFly 26 server.

When we attempt to send a message, we receive the following error in both WebLogic and WildFly logs:

javax.jms.JMSSecurityException: AMQ229031: Unable to validate user from /host:port. Username: null; SSL certificate subject DN: unavailable

It seems the problem is related to authentication on the connection factory used by WebLogic. I can't figure out how or where to correctly set the username and password so that WebLogic passes them to WildFly.


WildFly Configuration

Below is the relevant part of my standalone-full.xml configuration (ActiveMQ subsystem):

        <subsystem xmlns="urn:jboss:domain:messaging-activemq:13.1">
            <server name="default">
                <security elytron-domain="ApplicationDomain"/>
                <statistics enabled="${wildfly.messaging-activemq.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
                <security-setting name="#">
                    <role name="userApplication" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
                </security-setting>
                <address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
                <http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
                <http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
                    <param name="batch-delay" value="50"/>
                </http-connector>
                <in-vm-connector name="in-vm" server-id="0">
                    <param name="buffer-pooling" value="false"/>
                </in-vm-connector>
                <remote-connector name="netty-connector" socket-binding="messaging"/>
                <acceptor name="netty-acceptor" factory-class="org.apache.activemq.artemis.core.remoting.impl.netty.NettyAcceptorFactory" socket-binding="messaging"/>
                <http-acceptor name="http-acceptor" http-listener="default"/>
                <http-acceptor name="http-acceptor-throughput" http-listener="default">
                    <param name="batch-delay" value="50"/>
                    <param name="direct-deliver" value="false"/>
                </http-acceptor>
                <in-vm-acceptor name="in-vm" server-id="0">
                    <param name="buffer-pooling" value="false"/>
                </in-vm-acceptor>               
                <jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
                <jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
                <jms-queue name="testQueueWildflyToWls" entries="java:jboss/exported/jms/queue/testQueue_wildfy_to_wls"/>
                <jms-queue name="testQueueWlsToWildfly" entries="java:jboss/exported/jms/queue/testQueue_wls_to_wildfly"/>
                <connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
                <connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
                <connection-factory name="RemoteTcpConnectionFactory" entries="java:jboss/exported/jms/RemoteTcpConnectionFactory" connectors="netty-connector"/>
                <pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
            </server>
        </subsystem>


<!-- Other configurations -->

    <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
        <socket-binding name="ajp" port="${jboss.ajp.port:8009}"/>
        <socket-binding name="messaging" port="61616"/>
        <socket-binding name="http" port="${jboss.http.port:8088}"/>
        <socket-binding name="https" port="${jboss.https.port:8443}"/>
        <socket-binding name="iiop" interface="unsecure" port="3528"/>
        <socket-binding name="iiop-ssl" interface="unsecure" port="3529"/>
        <socket-binding name="management-http" interface="management" port="${jboss.management.http.port:9990}"/>
        <socket-binding name="management-https" interface="management" port="${jboss.management.https.port:9993}"/>
        <socket-binding name="txn-recovery-environment" port="4712"/>
        <socket-binding name="txn-status-manager" port="4713"/>
        <outbound-socket-binding name="mail-smtp">
            <remote-destination host="${jboss.mail.server.host:localhost}" port="${jboss.mail.server.port:25}"/>
        </outbound-socket-binding>
    </socket-binding-group>


WebLogic Configuration

Foreign Server configuration:

    <foreign-server name="ForeignServer">
    <default-targeting-enabled>true</default-targeting-enabled>
    <foreign-destination name="remoteQueueWlsToWildfly">
        <local-jndi-name>jms/app/remoteQueueWlsToWildfly</local-jndi-name>
        <remote-jndi-name>jms/queue/testQueue_wls_to_wildfly</remote-jndi-name>
    </foreign-destination>
    <foreign-destination name="remoteQueueWildflyToWls">
        <local-jndi-name>jms/app/remoteQueueWildflyToWls</local-jndi-name>
        <remote-jndi-name>jms/queue/testQueue_wildfy_to_wls</remote-jndi-name>
    </foreign-destination>
    <foreign-connection-factory name="WildflyConnectionFactory">
        <local-jndi-name>jms/app/remoteFactory</local-jndi-name>
        <remote-jndi-name>jms/RemoteConnectionFactory</remote-jndi-name>
        <username>userApplication</username>
        <password-encrypted>{AES}******************</password-encrypted>
        <connection-health-checking>enabled</connection-health-checking>
    </foreign-connection-factory>
    <initial-context-factory>org.wildfly.naming.client.WildFlyInitialContextFactory</initial-context-factory>
    <connection-url>http-remoting://localhost:8088</connection-url>
    <jndi-properties-credential-encrypted>{AES}*********************</jndi-properties-credential-encrypted>
    <jndi-property>
        <key>jboss.naming.client.ejb.context</key>
        <value>true</value>
    </jndi-property>
    <jndi-property>
        <key>java.naming.security.principal</key>
        <value>userApplication</value>
    </jndi-property>
</foreign-server>

How can I configure WebLogic 12c to send the username and password when connecting to a remote JMS queue on WildFly 26? Ideally, I want to do this through Foreign Server configuration or another method that does not require changes to application code.


What I've Tried:


Solution

  • TL;DR

    Don’t create the ConnectionFactory manually in code.
    Instead, inject it with @Resource so WebLogic uses the credentials from the Foreign Server configuration.


    I was able to find the root cause for this a few weeks ago, and now I’m taking the time to close this topic.

    The issue was actually in the application source code, which I was initially trying to avoid changing.

    The application was creating the ConnectionFactory like this:

    public static void sendMessage(final Object msg, final String queueName) throws Exception {
        String connectionFactoryName = "ConnectionFactoryName";
        ServiceLocator sl = ServiceLocatorFactory.getServiceLocator(queues);
        
        try {
            QueueConnectionFactory connectionFactory = sl.getQueueConnectionFactory(connectionFactoryName);
            QueueConnection connection = connectionFactory.createQueueConnection();
    
            [...]
        }
    }
    

    When I changed the line to explicitly provide username and password:

    QueueConnection connection = connectionFactory.createQueueConnection("user", "password");
    

    the connection was authenticated successfully.


    So, when you create a ConnectionFactory directly in code without passing user and password as arguments, the application will still retrieve all configuration from the Foreign Server (such as Remote JNDI and Remote ConnectionFactory), except the user/password values defined there.


    Final Fix

    The real fix was to avoid creating the ConnectionFactory in code at all. Instead, I injected it directly into the MDB EJB using @Resource. This way, the application receives the complete ConnectionFactory with the authentication provided inside the Foreign Server:

    @Resource(lookup = "jms/app/remoteFactory")
    private QueueConnectionFactory connectionFactory;