So I'm working with Spring Boot to implement a service API for interop with a third party. I'm using payload-based routing because they are not sending SOAPAction or any addressing information. However, when a request comes in, it's trying to map one of the incoming encryption-related elements and failing to map. I think the problem is that my friends at the third party are element-encrypting the operation element:
<n1:body>
<n2:SomeOperation> // This is
...some content... // all
</n3:SomeOperation> // encrypted
</n1:body>
From my reading, Spring attempts to map to an endpoint before encryption, so payload mapping will never work. I could use #Action or #SoapAction, but they are using Soap 1.2 (so no action header) and not using addressing. I have also verified that the Wss4SecurityInterceptor is being added, but is never called when a request is made.
Is my assessment/understanding of the situation correct? Can anyone think of any workarounds, because having the remote party change anything is nearly impossible.
A related question (hopefully asking one is not too unorthodox): I was trying to make my test client only encrypt the content of my operation element, but my setSecurementEncryptionParts() call is not playing nice. Here's the outgoing payload(from the console):
<ns2:EchoTestInput xmlns:ns2="http://xml.netbeans.org/schema/EchoTestSchema">
<ns2:valueIn>Quack</ns2:valueIn>
</ns2:EchoTestInput>
And here's the call to setSecurementEncryptionParts()
securityInterceptor.setSecurementEncryptionParts("{Content}{http://xml.netbeans.org/schema/EchoTestSchema}EchoTestInput");
I thought this should all be easy, but I guess not. Thanks a million in advance!
Related
Consider a POST/PUT REST API (using DRF).
If the server receives request1 and within a couple of ms request2 with identical everything to request1 (duplicate request), is there a way to avoid the request2 to be executed using some Django way? Or Should I deal with it manually by some state?
Any inputs would be much appreciated.
There isn't anything out of the box so you would need to write something your self potentially a piece of custom middleware (https://docs.djangoproject.com/en/3.0/topics/http/middleware/) would be best as then it would run over all of the requests. You would need to capture and exam the requests so you'd need a fast storage of some sort such as a memory store.
You could also look into the python asynco library - https://docs.python.org/3/library/asyncio-sync.html
Another possible solution would be using a FIFO message queue which is configured to support de-duplication based on content. This would turn the request into an deferred process though so it may not be suitable for your needs.
I want to write my own "ServletContainerInitializer" that adds my local filter to the ServletContext. And I also want to manage ordering of ServletContainerInitializer invocation so that my local filter will get register and hit by the request before the websocket upgrade filter.
I want to know how to initialize my local ServletContainerInitializer ?
First, ServletContextInitializer are not ordered, that feature is not part of the Servlet spec. You can't accomplish that part of your question. (maybe in a future version of the Servlet spec)
Next, filtering on WebSocket Upgrade requests is highly discouraged, and a cause for a large number of problems in WebSocket. You have to be very careful to not do any of the following.
Access anything on the Response object
Do not wrap the Request or Response objects
Do not access the Request input streams or readers
Do not access the Response output streams or writers
Do not add headers
Do not change headers
Do not access request HttpSession
Do not access request user principal
Do not access request authentication / authorization methods
Do not access request parts (multipart/form-data)
Do not access request parameters
Do not access ServletContext
Do not access request.getScheme or isSecure
Do not remove things from the request (attributes, headers, parameters, etc)
In short, the only safe things you can do are
request.getAttribute(String name)
request.getContextPath()
request.getCookies()
request.getHeader(String name)
request.getIntHeader(String name)
request.getLocalName()
request.getLocalPort()
request.getPathInfo()
request.getPathTranslated()
request.getQueryString()
request.getRemoteAddr()
request.getRemotePort()
request.getRequestURI()
request.getRequestURL()
request.getServerName()
request.getServerPort()
As all other accesses on the request or response objects will change the state of the request and prevent an upgrade.
The fact that Jetty has a WebSocketUpgradeFilter is just our choice on implementation for the JSR-356 (aka javax.websocket) spec. It is added by a server side ServletContextInitializer and is forced to be first, always.
In practice you should work with the expectation that upgrades occur before the Servlet processing (and this includes filters), as this is how the spec is written. There are open bugs against the spec about how interactions with filters and whatnot should be treated, but those are currently unanswered and loosely scheduled for a future version of the javax.websocket spec.
Future versions of Jetty will likely change from using a filter to using something internal that cooperates at the path mapping level, merging the logic from the Servlet spec and the WebSocket spec into a single new set of rules.
Since this question comes up often, i've ticked the community wiki flag.
The number one reason this gets asked is because there is some authentication or authorization logic built into a filter on your project.
If this is the case, you have 2 options.
Refactor out the authentication and/or authorization logic into a standalone classs, unassociated with your filter.
Build a new Filter and a new ServerEndpointConfig.Configurator that uses this now common logic to accomplish the end results you need. Note that you do not have access to the entire HttpServletRequest object when under a potential WebSocket upgrade, you only have access to the HandshakeRequest object contents. (you can see the restrictions now)
Use the Servlet spec, and containers properly and implement / configure Security at the container level, which will always execute before websocket or servlets or filters. Thus dropping your security based Filters entirely.
I have Spring WS which is creating a record in database after SOAP request, and then it should wait till response appear. (i have two tables in DB - requestTable -record is created when request to WS came, and responseTable - records are created by independent source). When Method detect that record linked with request appear in responseTable, WS send proper response.
Problem lies in synchronization because i can't ( actually i can but i don't want to) create a wait for n seconds thread, i want to make it using CAMEL, I read somewhere that CAMEL implements method that is proper for this kind of situation abut now I can't find it again.
And i have a question for You: Do you have a hint how i can do that?
I will post the way i did this.
Solution with using JMS channel between WS and Database what is described here works great:
Transparent Asynchronous Remoting via JMS
I m new to Camel and wondering how I can implement below mentioned use case using Camel,
We have a REST web service and lets say it has two service operations callA and callB.
Now we have ESB layer in the front that intercepts the client requests before hitting this actual web service URLs.
Now I m trying to do something like this -
Expose a URL in ESB that client will actually call. In the ESB we are using Camel's Jetty component which just proxies this service call. So lets say this URL be /my-service/scan/
Now on receiving this request #ESB, I want to call these two REST endpoints (callA and callB) -> Get their responses - resA and resB -> Aggregate it to a single response object resScan -> return to the client.
All I have right now is -
<route id="MyServiceScanRoute">
<from uri="jetty:http://{host}.{port}./my-service/scan/?matchOnUriPrefix=true&bridgeEndpoint=true"/>
<!-- Set service specific headers, monitoring etc. -->
<!-- Call performScan -->
<to uri="direct:performScan"/>
</route>
<route id="SubRoute_performScan">
<from uri="direct:performScan"/>
<!-- HOW DO I??
Make callA, callB service calls.
Get their responses resA, resB.
Aggregate these responses to resScan
-->
</route>
I think that you unnecessarily complicate the solution a little bit. :) In my humble opinion the best way to call two independed remote web services and concatenate the results is to:
call services in parallel using multicast
aggregate the results using the GroupedExchangeAggregationStrategy
The routing for the solution above may look like:
from("direct:serviceFacade")
.multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
.enrich("http://google.com?q=Foo").enrich("http://google.com?q=Bar")
.end();
Exchange passed to the direct:serviceFacadeResponse will contain property Exchange.GROUPED_EXCHANGE set to list of results of calls to your services (Google Search in my example).
And that's how could you wire the direct:serviceFacade to Jetty endpoint:
from("jetty:http://0.0.0.0:8080/myapp/myComplexService").enrich("direct:serviceFacade").setBody(property(Exchange.GROUPED_EXCHANGE));
Now all HTTP requests to the service URL exposed by you on ESB using Jetty component will generate responses concatenated from the two calls to the subservices.
Further considerations regarding the dynamic part of messages and endpoints
In many cases using static URL in endpoints is insufficient to achieve what you need. You may also need to prepare payload before passing it to each web service.
Generally speaking - the type of routing used to achieve dynamic endpoints or payloads parameters in highly dependent on the component you use to consume web services (HTTP, CXFRS, Restlet, RSS, etc). Each component varies in the degree and a way in which you can configure it dynamically.
If your endpoints/payloads should be affected dynamically you could also consider the following options:
Preprocess copy of exchange passed to each endpoint using the onPrepareRef option of the Multicast endpoint. You can use it to refer to the custom processor that will modify the payload before passing it to the Multicast's endpoints. This may be good way to compose onPrepareRef with Exchange.HTTP_URI header of HTTP component.
Use Recipient List (which also offers parallelProcessing as the Multicast does) to dynamically create the REST endpoints URLs.
Use Splitter pattern (with parallelProcessing enabled) to split the request into smaller messages dedicated to each service. Once again this option could work pretty well with Exchange.HTTP_URI header of HTTP component. This will work only if both sub-services can be defined using the same endpoint type.
As you can see Camel is pretty flexible and offers you to achieve your goal in many ways. Consider the context of your problem and choose the solution that fits you the best.
If you show me more concrete examples of REST URLs you want to call on each request to the aggregation service I could advice you which solution I will choose and how to implement it. The particularly important is to know which part of the request is dynamic. I also need to know which service consumer you want to use (it will depend on the type of data you will receive from the services).
This looks like a good example where the Content Enricher pattern should be used. Described here
<from uri="direct:performScan"/>
<enrich uri="ServiceA_Uri_Here" strategyRef="aggregateRequestAndA"/>
<enrich uri="ServiceA_Uri_Here" strategyRef="aggregateAandB"/>
</route>
The aggregation strategies has to be written in Java (or perhaps some script language, Scala/groovy? - but that I have not tried).
The aggregation strategy just needs to be a bean that implements org.apache.camel.processor.aggregate.AggregationStrategy which in turn requires you to implement one method:
Exchange aggregate(Exchange oldExchange, Exchange newExchange);
So, now it's up to you to merge the request with the response from the enrich service call. You have to do it twice since you have both callA and callB. There are two predefined aggregation strategies that you might or might not find usefull, UseLatestAggregationStrategy and UseOriginalAggregationStrategy. The names are quite self explainatory.
Good luck
I currently have a BizTalk 2006 (r1) application which receives XML from a SQL stored proc using the SQL adapter. It maps this to another schema before sending out to a 3rd party. The send port uses a custom pipeline component which converts the XML to a flat file - in the format required by the customer. I don't use any orchestration, this is a pure message based solution.
This all works great when sending via FTP. However, the 3rd party have now requested that I push the message to a web service they hosy. I haven't received the WSDL yet but can assume that the method I'll be calling simply receives a string as a single parameter.
Could anyone advise on the best way to approach this please? I have created a simple web service stub. I then followed Recipe 6-11 from the excellent BizTalk 2006 Recipes book, generating a proxy class using wsdl.exe which I then reference from the "web service" tab of the SOAP send port. However, when processing an order I get the following message in the event log:
Could not load type 'WSProxy' from assembly 'Direct.IS.Payment.Components, Version=3.1.145.0, Culture=neutral, PublicKeyToken=dc03da781bea1472'.".
The type must derive from System.Web.Services.Protocols.SoapHttpClientProtocol.
The type must have the attribute System.Web.Services.WebServiceBindingAttribute. ".
Next step will be for me to play around with the proxy so that it address the derive and attribute issues mentioned in the even log message. However, I can't help but think that there must be an easier way?
Thanks
The custom pipeline component you have created is not producing a message that is suitable for SOAP transmission. Not knowing what the end customer is going to do, I'd hold off on trying ot make SOAP work. In the mean time, just spin up an ASPX page with the following code:
private void Page_Load(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(page.Request.InputStream);
String xmlData = reader.ReadToEnd();
}
Add code to write XMLData to a DB or to a text file or something to see what it is. This is very crude and does not send a response code. It should get you started.