Can the WSO2 ESB JMS transport add custom JMS headers - jms

I am trying to add some custom JMS headers, required by another 3rd party system to the outgoing message.
I have tried adding the following property mediator:
<property xmlns="http://ws.apache.org/ns/synapse" name="HEADER" value="VALUE" scope="transport" type="STRING"/>
The JMS broker (ActiveMQ) is receiving the HEADER:VALUE but treating it as a property, rather than a header
I know there are reserved JMS header keywords, such as JMS_TIME_TO_LIVE, however these aren't well documented.
I suspect I may have to add something to the TRANSPORT_HEADERS map, however the documentation states it is filled from the client request, and again, these show as properties in ActiveMQ rather than headers

The original was working correctly, and adding the values to the User defined properties collection of the JMS message. This is the correct place to add application headers.
<property xmlns="http://ws.apache.org/ns/synapse" name="HEADER" value="VALUE" scope="transport" type="STRING"/>
The issue was a configuration error in the 3rd party tool.

Related

In Mule 4 using JMS Connector how to remove the RFH Header

I am using JMS Connector to connect to IBM MQ. If I use IBM MQ Connector I have option (targetClient="NO_JMS_COMPLIANT") to disable RFH Header from the message. How can I achieve the same thing using the JMS Connector. My JMS config looks like below
<jms:config name="JMS_Config" doc:name="JMS Config" doc:id="b675becf-06f3-4847-bb95-4f468d5353ea" >
<jms:generic-connection specification="JMS_2_0" connectionFactory="WMQ_ConnectionFactory" />
</jms:config>
Connection Factory looks like this:
<bean id="WMQ_ConnectionFactory" class="com.ibm.mq.jms.MQConnectionFactory" name="WMQ_ConnectionFactory">
<property name="transportType" value="1" />
<property name="hostName" value="MQ-SLQ01"/>
<property name="port" value="1414"/>
<property name="queueManager" value="SLQ01"/>
<property name="channel" value="*******"/>
</bean>
JMS Connector config looks like this:
<jms:publish-consume doc:name="Publish consume" doc:id="b1d40cc6-deb0-42f0-aa50-4b230d843794" config-ref="JMS_Config" destination="P2.REQUEST" sendCorrelationId="ALWAYS">
<jms:message >
<jms:reply-to destination="P2.REPLY" />
</jms:message>
</jms:publish-consume>
I have tried adding request queue name with P2.REQUEST?targetClient=1. I could not see any changes.
I doubt the JMS connector allows to select a non-JMS compatible mode that is specific to a broker (IBM MQ). It a generic connector which provides no broker specific features. You should be using the IBM MQ connector for that that already provides that specific feature.
And alternate action you could take would be to disable the RFH2 header by using a setting on the queue.
ALTER QLOCAL(P2.REQUEST) PROPCTL(NONE)
This will strip all properties (RFH2 header) off the message before delivering it to any application that doesn't supply a message handle.

Missing soap action :: Spring Integration

I am working on a spring integration component where I posting data to external third-party URL. and Its is working fine with the below code.
<!-- language: lang-xml -->
<int:chain id="channe.id"
input-channel="request.in"
output-channel="reply.channel">
<int-ws:header-enricher>
<int-ws:soap-action
value="${service.soapaction}" />
</int-ws:header-enricher>
<int-ws:outbound-gateway
id="invoker.ws.outbound.gateway"
ignore-empty-responses="true" message-sender="message.sender"
interceptors="${SecurityInterceptor}"
message-factory="${mmessageFactory}"
uri="${protocol}://${host}:${port}/{endpoint}">
<int-ws:uri-variable name="endpoint"
expression="headers.endpoint" />
<int-ws:request-handler-advice-chain>
<ref bean="commonRetryAdviceBean" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>
</int:chain>
Below is payload received by third part api.
<MessageLogTraceRecord>
<HttpRequest xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<Content-Length>9381</Content-Length>
<Content-Type>text/xml; charset=UTF-8</Content-Type>
<Accept>text/xml</Accept>
<Accept-Encoding>gzip</Accept-Encoding>
<Host>myhost</Host>
<User-Agent>Jakarta Commons-HttpClient/3.1</User-Agent>
<SOAPAction>"http://www.mysoap.com/action/update"</SOAPAction>
</WebHeaders>
Now, I have to add an additional security feature and send the API key in the HTTP header or soap header. SO I modified my code as below. Now I can see API key is sent as soap header but some how SOAPAction is going empty, not sure why.
below is the modified code to send api ket as part of soap header.
<int:chain id="channe.id"
input-channel="request.in"
output-channel="reply.channel">
<int-ws:header-enricher>
<int-ws:soap-action
value="${service.soapaction}" />
</int-ws:header-enricher>
<int-ws:outbound-gateway
id="invoker.ws.outbound.gateway"
ignore-empty-responses="true" message-sender="message.sender"
interceptors="${SecurityInterceptor}"
message-factory="${mmessageFactory}"
mapped-request-headers="soapHeaderMapper"
uri="${protocol}://${host}:${port}/{endpoint}">
<int-ws:uri-variable name="endpoint"
expression="headers.endpoint" />
<int-ws:request-handler-advice-chain>
<ref bean="commonRetryAdviceBean" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>
</int:chain>
<bean id="soapHeaderMapper"
class="org.springframework.integration.ws.DefaultSoapHeaderMapper">
<property name="requestHeaderNames">
<list>
<value>api-key</value>
</list>
</property>
</bean>
After adding mapped-request-headers now I am getting
org.springframework.messaging.MessagingException: The message could not be processed because the action '' is invalid or unrecognized.; nested exception is org.springframework.ws.soap.client.SoapFaultClientException: The message could not be processed because the action '' is invalid or unrecognized., failedMessage=GenericMessage
when I checked the payload received by thirdparty api I can see SOAP action is empty I am not sure why.
Please help me.
Thanks.
<QueryString></QueryString>
<WebHeaders>
<Content-Length>9463</Content-Length>
<Content-Type>text/xml; charset=UTF-8</Content-Type>
<Accept>text/xml</Accept>
<Accept-Encoding>gzip</Accept-Encoding>
<Host>myhost</Host>
<User-Agent>Jakarta Commons-HttpClient/3.1</User-Agent>
<SOAPAction>""</SOAPAction>
</WebHeaders>
</HttpRequest>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header api-key="dummy-123455555uuuuuuuuuuuqwert">
The mapped-request-headers="soapHeaderMapper" is wrong configuration. It is exactly about names, but in your case you try to make a reference to the DefaultSoapHeaderMapper bean definition.
Consider to use:
<xsd:attribute name="header-mapper">
<xsd:annotation>
<xsd:documentation>
Reference to a SoapHeaderMapper implementation
that this gateway will use to map between Spring Integration
MessageHeaders and the SoapHeader.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.ws.SoapHeaderMapper"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
instead.
Also there is the with your header names to map: when you configure some custom header names, all the standard headers are missed. So, alongside with the api-key, you need to consider include the mentioned ws_soapAction name as well.

WSO2 CEP IBM MQ and transport.jms.ConcurrentConsumers

I have a WSO2 CEP configured with Input Event Adaptor set to listen on a IBM WebSphere MQ queue. Below there is a conf in xml:
<inputEventAdaptor name="WEBSPHEREMQ" statistics="disable" trace="disable" type="jms" xmlns="http://wso2.org/carbon/eventadaptormanager">
<property name="java.naming.provider.url">file:/opt/bindings</property>
<property name="transport.jms.SubscriptionDurable">false</property>
<property name="java.naming.factory.initial">com.sun.jndi.fscontext.RefFSContextFactory</property>
<property name="transport.jms.ConnectionFactoryJNDIName">MQ_JMS_MANAGER</property>
<property name="transport.jms.DestinationType">queue</property>
</inputEventAdaptor>
and an event builder with queue set:
<from eventAdaptorName="WEBSPHEREMQ" eventAdaptorType="jms">
<property name="transport.jms.Destination">MSCRM_IN_JMS_QUEUE</property>
</from>
I want to increase transport.jms.ConcurrentConsumers to speed up CEP performance results. Where do I need to put this parameter? I have tried in event adaptor and in event builder but it doesn't work.
Thanks a lot for any help!:)
Peter
Sorry at the moment, there is no any way to pass this property out of the box to jms adaptor. But I strongly believe this is a good addition for jms adaptor. We are doing some improvements related to this by aiming next release.. I have created a jira [1] to track this..
[1] https://wso2.org/jira/browse/CEP-884
you have two option at the moment, improve the current input jms adaptor by fixing in the source or write a custom jms adaptor for you need..
Thanks,Mohan

Direct exchange doesn't work with default routingKey

I don't understand something.
I'm using Spring Integration to send and receive messages from RabbitMQ.
My topology is pretty simple:
One JVM produce messages using the RabbitTemplate of Spring
<rabbit:template id="rabbitTemplate" connection-factory="rabbitConnectionFactory" />
<bean id="amqpTemplate" parent="rabbitTemplate">
<property name="queue" value="${queue.name}" />
<property name="routingKey" value="${queue.name}" />
</bean>
RabbitMQ queue receive the message
<rabbit:queue name="${queue.name}" durable="true" />
Another JVM consume the message (to launch a Spring-Batch job, but that's not the point):
<int-amqp:inbound-channel-adapter
queue-names="${queue.name}"
channel="amqp-requests"
connection-factory="rabbitConnectionFactory" />
The send method used is:
/**
* Convert a Java object to an Amqp {#link Message} and send it to a default exchange with a default routing key.
*
* #param message a message to send
* #throws AmqpException if there is a problem
*/
void convertAndSend(Object message) throws AmqpException;
It works fine but according to the documentation, I don't think the routingKey is mandatory in my usecase. I don't know why someone put a routingKey.
So I tried to remove the routingKey:
<bean id="amqpTemplate" parent="rabbitTemplate">
<property name="queue" value="${queue.name}" />
</bean>
Then I can still send the messages to the queue, but they are never consumed anymore!
Can someone explain me what is going on?
Can't I send messages from one JVM to another without a routingKey?
...but according to the documentation, I don't think the routingKey is mandatory...
Which "documentation" are you referring to?
With AMQP, producers do not know about queues; they send messages to various types of exchanges which have bindings for routing to queues.
Maybe you are mis-understanding the notion of the default exchange, to which every queue is bound, with a routing key equal to its queue name.
This allows simple routing to specific queues (by way of their names). The default exchange is a convenience to provide a quick on-ramp to amqp messaging. This works fine, but you might want to consider using explicitly declared exhanges instead, because it further decouples the producer from the consumer. With the default exchange the producer has to know the name of the queue that the consumer is listening on.
Further, on the RabbitTemplate, the queue property is only used for receiving (consuming) messages, it has no bearing on sending messages; as I said producers don't know about queues.
You should use the following...
<bean id="amqpTemplate" parent="rabbitTemplate">
<property name="routing-key" value="${queue.name}" />
</bean>

WS-Security Websphere Configuration

I'm trying to develop a web service that uses WS-Security using Websphere 7 and JAX-WS. Looking through some guides, it appears that I MUST create a application server user registry and maintain username/passwords inside of that server. Is there anyway to avoid having to create usernames in the server itself and somehow capture the header and do validation based upon another a custom security configuration like a single sign-on?
I'm able to create a handler to get the header, but when mustUnderstands is set to 1 in the request (which is mandatory), it gets rejected before my handler sees the message.
I'm only looking to use the UsernameToken part of WS-Security.
Any help is appreciated.
An example of my request
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" Id="unt_20">
<wsse:Username>some_username</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">some_password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
...body...
</soapenv:Body>
</soapenv:Envelope>
Is it possible to create a custom security implementation so I can use my existing user validation scheme?
It would appear that I can implement a custom user registry that can interact with the security implementation of my choice. A link to the IBM article:
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/ae/tsec_useregistry.html
Another possible answer is to create a Trust Association Interceptor (TAI). This basically extends your current security.
Here is a useful link to get started:
http://www.ibm.com/developerworks/websphere/techjournal/0508_benantar/0508_benantar.html
You can use the out-of-box WS-Security runtime with policy/bindings to achieve this, but you must write custom code to override the default behavior of checking the user registry for UsernameTokens.
See this article for using your own authentication mechanism when consuming the UsernameToken:
Configuring a UsernameToken caller configuration with no registry interaction
See this article if you want to also create WebSphere credentials based on the user name in that token:
Replacing the authentication method of the UsernameToken consumer using a stacked JAAS login module
Can you elaborate on what you want to achieve?
The WAS Server needs to validate the username and password that comes in the header against its user registry (which could an LDAP, File based registry etc).
LTPA tokens (which are used by WebSphere and related products for SSO) can be used too.
If you spell out your requirements, folks here will be able to help you out.
HTH
Manglu
JAX-WS should allow you to have a custom interceptor.
Take a look at this spring config to see how I have added an interceptor to the service endpoint.
<jaxws:endpoint id="pqdws"
implementor="#Atypon"
address="/pqdws"
publishedEndpointUrl="#ws_webapp_url_ext#">
<jaxws:properties>
<entry key="exceptionMessageCauseEnabled" value="true"/>
<entry key="Content-length"
</jaxws:properties>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef">
<ref bean="passwordCallback"/>
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
<bean id="passwordCallback"
class="access.ws.ServerPasswordCallback">
<property name="username" value="#ws_sec_username#"/>
<property name="password" value="#ws_sec_password#"/>
</bean>
The interceptor can then do whatever you wish including calling out to an external service for authentication.

Resources