Securing Camel CXFRS consumer with SAML - cxf

I'm attempting to secure a CXFRS consumer endpoint defined in camel with SAML Web SSO using the cxf SamlRedirectBindingFilter. Below is the spring XML defining the route/endpoints:
<cxf:bus>
<cxf:features>
<cxf:logging/>
</cxf:features>
</cxf:bus>
<bean id="stateManager" class="org.apache.cxf.rs.security.saml.sso.state.EHCacheSPStateManager">
<constructor-arg ref="cxf"/>
</bean>
<bean id="redirectGetFilter" class="org.apache.cxf.rs.security.saml.sso.SamlRedirectBindingFilter">
<property name="idpServiceAddress" value="http://carnold-linux.ptcnet.ptc.com:9093/idp/profile/SAML2/Redirect/SSO"/>
<property name="assertionConsumerServiceAddress" value="/racs/sso"/>
<property name="stateProvider" ref="stateManager"/>
<property name="addWebAppContext" value="false"/>
</bean>
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/spring">
<route id="proxyRoute">
<from uri="cxfrs://http://0.0.0.0:9092/app?resourceClasses=com.company.FooResource,com.company.BarResource&providers=#redirectGetFilter"/>
...rest of route
The issue I'm having is that even though I added the SamlRedirectFilter to the providers for the endpoint - it's not redirecting/authenticating. Any thoughts on what might be the issue?

Current camel release version doesn't support to configure the provides from the uri.
You can configure the provider by using the cxf:rsServer just like this
<cxf:rsServer id="rsServer" address="http://0.0.0.0:9092/app"
>
<cxf:providers>
<ref bean="redirectGetFilter"/>
</cxf:providers>
<cxf:serviceBeans>
<ref bean="fooResource"/>
<ref bean="barResource"/>
</cxf:serviceBeans>
</cxf:rsServer>
<bean id="fooResource" class="com.company.FooResource"/>
<bean id="barResource" class="com.company.BarResource"/>
<camelContext id="camel" trace="false" xmlns="http://camel.apache.org/schema/spring">
<route id="proxyRoute">
<from uri="cxfrs://bean:rsServer"/>
...rest of route

Related

OnException does not work for Camel CXF used as Producer

Camel / CXF versions used:
<camel-version>2.18.1</camel-version>
<cxf-version>3.1.7</cxf-version>
Using Spring DSL to define routes. Sample code:
<cxf:cxfEndpoint address="{{ws.url}}" id="wsCallCxfBean"
serviceClass="com.some.package.GeneratedClassEndpoint">
<cxf:properties>
<entry key="username" value="${ws.username}" />
<entry key="password" value="${ws.password}" />
</cxf:properties>
<cxf:outInterceptors>
<ref bean="logOutbound" />
</cxf:outInterceptors>
</cxf:cxfEndpoint>
Camel Context:
<camel:errorHandler id="deadLetterErrorHandler" type="DeadLetterChannel" deadLetterUri="log:dead" />
<camelContext id="camelCxtId" trace="{{trace}}" handleFault="true" errorHandlerRef="deadLetterErrorHandler"
xmlns="http://camel.apache.org/schema/spring">
<onException id="onCContextException_Common">
<exception>java.lang.Exception</exception>
<redeliveryPolicy maximumRedeliveries="2" />
<!-- mark this as handled -->
<handled>
<constant>true</constant>
</handled>
<to id="onCContextExceptionHandling_Common" pattern="OutOnly" uri="vm:onRouteErrorOutMsgCaught" />
</onException>
.....
Route:
<route id="wsCall_RouteID" handleFault="true">
<description>Call the web service</description>
<from id="vmFrom_id" uri="vm:fromPOJOVM" />
<to id="wsCall_id" uri="cxf:bean:wsCallCxfBean" />
<onException id="onRouteException_WS">
<exception>java.lang.Exception</exception>
<redeliveryPolicy maximumRedeliveries="2" />
<handled>
<constant>true</constant>
</handled>
<to id="onRouteExceptionHandling_WS" pattern="OutOnly"
uri="vm:onRouteErrorOutMsgCaught" />
</onException>
</route>
Issue that I am facing:
Whenever exception is thrown in CXF, it is not handled by the Camel onException.
I can see the exception in the log. Sample exception from log (truncated):
WARN PhaseInterceptorChain:449 - Interceptor for {http://someaddress}WSEndpointService#
{http://someaddress}WSOperation has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Marshalling Error: Connection timed out: connect
at org.apache.cxf.jaxb.JAXBEncoderDecoder.marshall(JAXBEncoderDecoder.java:266)
...
Caused by: javax.xml.bind.MarshalException
- with linked exception:
[java.net.ConnectException: Connection timed out: connect]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
... 20 more
Caused by: java.net.ConnectException: Connection timed out: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
...
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323)
I have tried adding handleFault="true" in my camel context and Route - but that did not help.
How can I catch the exception thrown in CXF (for eg: the timeout, unknown host etc) in my camel route?
Thanks

Setting timeout for Apache Camel CXF consumer component

I want to set timeout for Apache Camel CXF consumer component.
My code looks something like:
<route>
<from uri="direct:NDS/getUserInformation" />
<to uri="freemarker:file:/application/DT/adapter/NDSLookupService.ftl" />
<bean ref="ndsServiceLogger" method="logNDSRequest" />
<setHeader headerName="SOAPAction">
<simple>getLookUpServiceDetails</simple>
</setHeader>
<bean ref="ndsServiceLogger" method="logNDSServiceStartTime" />
<toD uri="${headers.nds_url}?wsdlURL=/application/DT/adapter/NDSLookupService.wsdl&serviceName={http://webservices.lookup.sdp.bharti.ibm.com}NDSLookupServiceService&portName={http://webservices.lookup.sdp.bharti.ibm.com}NDSLookupService&dataFormat=MESSAGE" />
<bean ref="ndsServiceLogger" method="logNDSServiceEndTime" />
<bean ref="ndsServiceLogger" method="logNDSResponse" />
<convertBodyTo type="java.lang.String" />
</route>
How about to try properties http.connection.timeout and
http.receive.timeout?
UPD: it does not work... I can just give you ideas where to go...
I use CXF bus for endpoints and Asynchronous transport (doc at Asynchronous Client HTTP Transport .
It is possible to set timeouts there like below.
<cxf-core:bus bus="bus-common-outbound">
<cxf-core:properties>
<spring:entry key="use.async.http.conduit" value="true" />
<spring:entry key="org.apache.cxf.transport.http.async.usePolicy" value="ALWAYS" />
<spring:entry key="org.apache.cxf.transport.http.async.SO_TIMEOUT" value="45000" />
</cxf-core:properties>
</cxf-core:bus>
and endpoint has property "bus" pointed to that by its "bus" property like: bus=bus-common-outbound
maybe you can use something like that or dig deeper for default synchronous transport...

No message body writer has been found for class org.apache.cxf.message.MessageContentsList, ContentType: application/xml

<cxf:rsServer id="rsServer" address="/services"
serviceClass="com.mayank.restservice.resource.RestfulResource">
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</cxf:providers>
</cxf:rsServer>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxfrs:bean:rsServer" />
<to uri="log:body?level=INFO" />
<to uri="activemq:queue:testQueue" pattern="InOnly" />
</route>
</camelContext>
<!-- ActiveMQ-beans definition -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
I have implemented the rest service using camel-cxf component support to route the response to activemq queue. Now when running the services url i get No message body writer has been found for class org.apache.cxf.message.MessageContentsList, ContentType: application/xml
message.
Below is my RestResource class.
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import com.mayank.restservice.model.ChequeDetails;
import com.mayank.restservice.service.RestfulService;
public class RestfulResource {
private RestfulService restfulservice;
public void setRestfulservice(RestfulService restfulservice) {
this.restfulservice = restfulservice;
}
#Path("post")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_XML)
public ChequeDetails persistDB(ChequeDetails chequedetails){
return restfulservice.persistDB(chequedetails);
}
}
For testing when I tried using #Produce(APPLICATION_JSON) I get a success response.
Not sure is this a problem from camel-cxf or in my application?
It looks like a JAXB configuration problem. Have you configured it for JSON support ?
http://cxf.apache.org/docs/jax-rs-data-bindings.html#JAX-RSDataBindings-JSONsupport
Example of configuration :
<beans xmlns:util="http://www.springframework.org/schema/util">
<bean id="jaxbProvider" class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
<property name="namespaceMap" ref="jsonNamespaceMap"/>
</bean>
<util:map id="jsonNamespaceMap" map-class="java.util.Hashtable">
<entry key="http://www.example.org/books" value="b"/>
</util:map>
/<beans>

how to pass Map in camel context in jbpm component

look at the location JBPMComponentIntegrationTest
.setHeader(JBPMConstants.PARAMETERS, constant(map))
so them map is passed as map in java route.
If i want to pass the same via xml is there a way ?
<camel:setHeader headerName="CamelJBPMParameters">
<camel:constant>????</camel:constant>
</camel:setHeader>
I could not find any example over internet.
If you are using a spring context you could simply initialize the map then reference it in your constant file. I am not 100% familiar with the xml camel constructs but it should look similar to this:
<camelContext id="myContext" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<setHeader headerName="theHeader">
<!-- not sure if the ref keyword is valid might have to adjust syntax -->
<constant ref="maps" />
</setHeader>
<to uri="mock:result"/>
</route>
</camelContext>
<property name="maps">
<map>
<entry key="Key 1" value="1" />
<entry key="Key 2" value="2" />
<entry key="Key 3" value="3" />
</map>
</property>

Blueprint, Apache Camel and cxfrs

I am trying to develop a rest service using blueprint, apache camel and apache cxf-rs - where the service implementation will be handled by camel.
The problem is the rest endpoint seems to not get allocated to camel.
This is the exception I get:
error occurred during starting Camel: CamelContext(blueprintContext)
due There is an endpoint already running on /crm.
My blueprint is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xmlns:cxf="http://cxf.apache.org/blueprint/core"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<jaxrs:server id="customerService" address="/crm" staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref component-id="customerSvc"/>
</jaxrs:serviceBeans>
<jaxrs:features>
<bean class="io.fabric8.cxf.endpoint.SwaggerFeature"/>
<bean class="io.fabric8.cxf.endpoint.ManagedApiFeature"/>
</jaxrs:features>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="customerSvc" class="restfuse.CustomerService"/>
<cxf:bus>
<cxf:features>
<cxf:logging />
</cxf:features>
</cxf:bus>
<camelContext id="blueprintContext" trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<route customId="true" id="timerToLog">
<from uri="cxfrs:bean:customerService"/>
<setBody>
<method ref="helloBean" method="hello"></method>
</setBody>
<log message="The message contains ${body}"/>
<to uri="mock:result"/>
</route>
I was having the same issue regarding cxf-rs web services using blueprint. For what I was able to see if you try to mix camel cxf component with cxf definitions, when camel contexts starts it tries to create the same cxf-rs enpoints twice, therefore it ends with: error occurred during starting Camel: CamelContext(blueprintContext) due There is an endpoint already running...
I managed to solve this changing <from uri=cxfrs:bean:mybean> to <from uri=direct:start> and modifying jaxrs:servicebean pojo injecting direct:start endpoint and sending received object as body.
Here is my code:
blueprint.xml
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
xmlns:cxf="http://cxf.apache.org/blueprint/core"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd
http://camel.apache.org/schema/blueprint/cxf http://camel.apache.org/schema/cxf/camel-cxf-blueprint.xsd
http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd">
<jaxrs:server id="rsAuthApiSvc"
address="http://localhost:9898/authservice"
staticSubresourceResolution="true">
<jaxrs:serviceBeans>
<ref component-id="pmAuthService"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
<bean id="pmAuthService" class="com.platamovil.platamovil.auth.rs.PMAuthService"/>
<camelContext trace="false" streamCache="true" id="authApiContext" xmlns="http://camel.apache.org/schema/blueprint">
<route id="restApiRoute">
<from uri="direct:start"/>
<log message="received from WS: ${body}"/>
<setBody>
<constant>{"status":"OK"}</constant>
</setBody>
</route>
</camelContext>
pmAuthService Bean
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.camel.EndpointInject;
import org.apache.camel.ProducerTemplate;
import com.platamovil.platamovil.auth.api.PMAuthMessage;
public class PMAuthService {
#EndpointInject(uri="direct:start")
ProducerTemplate producer;
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/authenticateclient")
public PMAuthMessage processAuthService(PMAuthMessage in_msg) throws Exception{
System.out.println("message arrived");
return producer.requestBody(in_msg).toString()
}
}
After this fix CamelContext starts without error and works perfectly. I hope this helps!
Using CXFRsServer instead of jaxrs server also solves this problem.

Resources