Intercepting Camel Endpoint Dynamically - apache-camel

I am trying to intercept an endpoint where the value of the URI matches some information in the exchange header.
Let say I have a field in the header called DatabaseName. I want to enforce that a specific route is only writing to the database specified in the header.
Can I do something like this?
interceptSendToEndpoint("mock:${in.header.DatabaseName}")
I tried that but it does not seem to work. What are my options?
I was also thinking of doing something like:
interceptSendToEndpoint("mock:*").when(...)?
But in this case, I am not sure if I can reference the URI of the intercepted node in the when expression.
Thanks

You can intercept using a wildcard and combine that with when to do what you want, see details at: http://camel.apache.org/intercept
The is a header on the Message with the key Exchange.INTERCEPTED_ENDPOINT (CamelInterceptedEndpoint) that has the endpoint uri that was intercepted. You can use that in the when to match the predicate. Something a like:
interceptSendToEndpoint("mock:*")
.when(simple("${header.CamelInterceptedEndpoint} == ${in.header.DatabaseName}"))
...

Use the recipientList instruction for this: http://camel.apache.org/how-do-i-use-dynamic-uri-in-to.html

Related

AssertionConsumerServiceURL from AuthnRequest not from Config

Noticed that the Saml2AuthnResponse Destionation is set based on the relyingParty.SingleSignOnDestination which is retrieved from a "configuration" (harcoded relyingParties array).
I think the Destination should be based on what is set in the AuthnRequest samlp:AuthnRequest -> AssertionConsumerServiceURL and use the relyingParty Destination maybe as a fallback if its missing from the AuthnRequest, but from what I see every AuthnRequest contains the ACS URL.
Or is there a reason why it is implemented this way ?
Thanks
It is part of the security only to replay known URLs/domains. Therefore it is important to configure the relyingParty.SingleSignOnDestination for each relying party.
To have a dynamic response URL you can extend the code to verify that the authnRequest.AssertionConsumerServiceUrl starts with the value in relyingParty.SingleSignOnDestination.
E.g. the value in relyingParty.SingleSignOnDestination could be "https://somedomain.com"
and thereby accept different authnRequest.AssertionConsumerServiceUrl like "https://somedomain.com/auth/AssertionConsumerService" or "https://somedomain.com/acs"

Apache Camel Interceptor with regular expression

This is my route. I want to send a file to an Azure blob. I want to set the name of the blob as the file name without extension. I also want to filter out the whitespaces from the file names. I am thinking of using an interceptor
from("file://C:/camel/source1").recipientList(simple("azure-blob://datastorage/container1/${header.fileName}?credentials=#credentials&operation=updateBlockBlob"))
I want to invoke the interceptor only for updateBlockBlob operatin
interceptSendToEndpoint("^(azure-blob:).+(operation=updateBlockBlob)").setHeader("fileName",simple("${file:onlyname.noext}")).convertBodyTo(File.class)
The above code works with interceptFrom().
I tried replacing the regular expression with wild card like azure* i.e interceptSendToEndpoint("azure*"). It did not work
Whats wrong with the above code? Is it because of recipientList?
Also what features does simple have to remove white space?
Is there a better way to generate blob names dynamically?
Here is the documentation from camel on interceptors.
http://camel.apache.org/intercept.html
interceptFrom that intercepts incoming Exchange in the route.
interceptSendToEndpoint that intercepts when an Exchange is about to
be sent to the given Endpoint.
So I suspect the Exchange is already formed and camel expects the url to be resolved.
So the header needs to be set before the exchange is created for the Azure end point.
I did the following. To set the header, I use the interceptFrom, and to convert the object into File I used the inteceptSendToEndPoint
interceptSendToEndpoint("^(azure-blob:).+(operation=updateBlockBlob)").convertBodyTo(File.class)
interceptFrom().setHeader("fileName",simple("${file:onlyname.noext}".replaceAll("[^a-zA-Z\d]")))
Managed to get rid of the whitespace too

Camel Restlet - Binding query parameters to message headers

Looking through Camel docs I couldn't find any way that allow me to bind the query parameters within the headers. For example :
Let's say I have an endpoint like that
http://localhost:8080/services/resource?filter=xxx
End I want to get that parameter from the header
exchange.getIn.().getHeaders().get('filter')
The query parameter 'filter' is not returned in the header. Anyone of you knows if this feature is coming by default in camel? I know I can build the binding by myself, but i am just looking for choose among camel-servlet (apparently that binding is implemented by default) and camel-restlet.
If you choose camel-restlet you can use the
restletBinding=#refName
to convert the query string parameters to headers.
The #refName is the bean ID of a RestletBinding object in the Camel Registry.

Camel: POST-request routing by URL-pattern

I'm trying to catch some POST-request, log a message (and maybe a body or params in future); then pass them further to booHost, so the client will get the result of the call:
from("restlet:http://localhost:8090/api/endpointFoo?restletMethod=post")
.log("oh, it's a message!")
.routeId("someAPI")
.to("http://booHost:8090/api/endpointFoo?bridgeEndpoint=true&restletMethod=post");
That works just GREAT.
But:
What I need is the URL-pattern that will work that way. I'm trying:
from("restlet:http://localhost:8090/api/{endpoint}?restletMethod=post")
.log("oh, it's a message!")
.routeId("someAPI")
.to("http://booHost:8090/api/{endpoint}?bridgeEndpoint=true&restletMethod=post");
The "from" shots when I make the post. The message is logged.
But "to" seems not to treat {endpoint} as a param - it treats it like a constant; so the result of that call fails.
I don't need hardcoded endpoints because booHost API should be extended in future without Camel changes.
In other words, I need all calls to http://localhost:8090/api/* to be catched and resent to http://booHost:8090/api/* on the same endpoint.
Maybe I should use another component? Or How can I make it this way?
Thanks.
Thanks to #vikingsteve I've started to read about recipientList.
I've modified my code according to this FAQ question
The final version looks like this:
from("restlet:http://localhost:8090/api/{endpoint}?restletMethod=post")
.log(LoggingLevel.INFO, "POST-request to /${headers.endpoint} was sent")
.routeId("someAPI")
.recipientList(simple("http://booHost:8090/api/${headers.endpoint}?bridgeEndpoint=true&restletMethod=post"));
It works as suggested.

Encoding url's the Play! Framework

Is there a way to make the Play! Framework ignore slashes and ? in parts of the URL?
Typically, if I have the following:
www.123.com/api/link/http:www.bla.com/?contenId=123&User=test
It won't work. In that case, what I would want to do is simply have the link in the last part of the URL in a String variable to save it. I suppose I can force the client to replace the / and ? by something else, but I would rather keep it simple.
My first thought was that maybe there is a way to configure the routing such that we have something like:
/api/link/{data}
where data would hold whatever remains of the URL. Can't find out how to do that though.
You can't have : / ? except your main URL. You should encode your parameter to append it to main URL. See URLEncoder for Java.
This is not a valid URL:
http://www.123.com/api/link/http://www.bla.com/?contenId=123&User=test
It must be:
http://www.123.com/api/link/http%3a%2f%2fwww.bla.com%2f%3fcontenId%3d123%26User%3dtest
Then you can pass it to {data} parameter and decode it in your handler method.

Resources