Camel CxfEndpoint set address doesnt work after first call - web-services

I want to set address every time i reach my endpoint bean. When i call setAddress first time it works, after that address and endpoint url changes but ws call gone to first addres. here is my code
#Bean
public CxfEndpoint xWSwithoutAddress() {
final CxfEndpoint endpoint = new CxfEndpoint();
endpoint.setServiceClass(IntegrationSoap.class);
return endpoint;
}
#Bean
#Scope(value="prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public CxfEndpoint xWS() {
XSettings settings = configFileManager.readSettings(XSettings.class);
final CxfEndpoint endpoint = xWSwithoutAddress();
endpoint.setAddress(settings.getWsdlAddress());
return endpoint;
}
and route
from("direct:getEbysServices")
.to("cxf:bean:xWS?wrapped=true&loggingFeatureEnabled=true");

Stopping and starting route solves my issue.
I give route an id
from("direct:getEbysServices")
.routeId("ebysRoute")
.to("cxf:bean:xWS?wrapped=true&loggingFeatureEnabled=true");
and when address changes i stop and start route.
camelContext.stopRoute("ebysRoute");
camelContext.startRoute("ebysRoute");

Related

HTTP session is not maintained between two localhosts (gwt/react client running on port 3000, local tomcat server running on 8080) bcz of CORS domain?

Did anybody faced the above issue, CORS cookie is not getting stored in the browser even after enabling the CORS on the server-side to accept the preflight request and return as accepted on the very first call. All the requests originate from clients who always hit the servers with a new HTTP session id. I felt like enabling the CORS works only against the secured domain like HTTPS, not HTTP.
I have verified the first request and response headers, the response has the proper JSESSIONID is passed as the Set-Cookie value. But the subsequent requests were not referencing this cookie.
solution 1: add this bean
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
solution 2: add this to your controller
#CrossOrigin(origins = { "http://localhost:3000" })
**like this:**
#CrossOrigin(origins = { "http://localhost:3000" })
public class RoleController {
#Autowired
private RoleService roleService;
}

Springboot SOAP service unmarshalling Issue with the response from WebServiceTemplate

I am really bugged with an unmarshalling issue with the response from the SOAP service. I am using springboot application and WebServiceTemplate for calling an existing SOAP service. I am using below code to set up beans for marshalling and webservicetemplate. Any help is highly appreciated.
On calling webServiceTemplate.marshalSendAndReceive(request); I am expecting TravelResponse object but it is giving me JAXBElement<TravelResponse> object as response. I need help to understand
1) why is it giving above response instead of TravelResponse
2) How to convert to TravelResponse
Code snippet below:
#Bean
Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setContextPath("com.cater.trip.simple_api.trip.v1");
return jaxb2Marshaller;
}
#Bean
public WebServiceTemplate webServiceTemplate() throws Exception {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMessageFactory(getMessageFactory());
webServiceTemplate.setMarshaller(jaxb2Marshaller());
webServiceTemplate.setUnmarshaller(jaxb2Marshaller());
webServiceTemplate.setDefaultUri(defaultUri);
webServiceTemplate.setMessageSender(getMessageSender());
return webServiceTemplate;
}
#Bean
public SaajSoapMessageFactory getMessageFactory() {
return new SaajSoapMessageFactory();
}
#Bean
public HttpComponentsMessageSender getMessageSender() {
return new HttpComponentsMessageSender();
}
#Override
public Object getData( ) {
ObjectFactory clientFac = new ObjectFactory();
TravelRequest request = populateRequest(clientFac);
TravelResponse res = (TravelResponse) webServiceTemplate.marshalSendAndReceive(request);
return res;
}
As per Spring's doc, WebServiceTemplate.marshalSendAndReceive(Object requestPayload)
Sends a web service message that contains the given payload, marshalled by the configured Marshaller. Returns the unmarshalled payload of the response message, if any.
This will only work with a default uri specified!
So, you can do this to return the expected response.
JAXBElement<TravelResponse> res = (JAXBElement<TravelResponse>) webServiceTemplate.marshalSendAndReceive(request);
return res.getValue();
Try JaxbIntrospector.getValue to get the actual response from JAXB element.
TravelResponse response = JaxbIntrospector.getValue(jaxbElement);

Forwarding requests to external endpoint from an CFX service

Currently I am fighting with the following problem:
I need to forward SOAP requests to an external service in special cases (decision based on tenantId provided in the SOAP message). I created an interceptor for this task to extract tenantId from the message request, get assignment (each tenantId is assigned to its own service instance running on a different server) and if no assignment is made, I need to process the request just as normal.
Currently I implemented on this way: I create HttpUrlConnection in the interceptor and forward the request to an external endpoint (in case there is an assignment) and take the outputStream of the response and send the response over HttpServletResponse.getOutputStream etc...
I also need to consider that the interceptor be used with various service (tenantId must be provided in the SOAP request).
I also read about Provider and Dispatch objects not sure how this should work.
Is there any way to get target service and port (QNames) from the incoming message?
I cannot use Camel at the moment (only CXF is allowed).
Maybe you can try something like this :
/** Your interceptor */
public void handleMessage(SoapMessage msg) throws Fault {
Exchange exchange = msg.getExchange();
Endpoint ep = exchange.get(Endpoint.class);
// Get the service name
ServiceInfo si = ep.getEndpointInfo().getService();
String serviceName = si.getName().getLocalPart();
XMLStreamReader xr = msg.getContent(XMLStreamReader.class);
if (xr != null) { // If we are not even able to parse the message in the SAAJInInterceptor (CXF internal interceptor) this can be null
// You have the QName
QName name = xr.getName();
SOAPMessage msgSOAP = msg.getContent(SOAPMessage.class);
// Read soap msg
if (msgSOAP != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
msgSOAP.writeTo(byteArrayOutputStream);
String encoding = (String) msg.get(Message.ENCODING);
String xmlRequest = new String(byteArrayOutputStream.toByteArray(), encoding);
}
// Forward to external service with JAX-RS implementation
Client client = ClientBuilder.newClient()
.target("http://your-target")
.path("/custom-path")
.request()
.post(Entity.entity(xmlRequest, MediaType.APPLICATION_XML));
}
}
Hope this help.

Cannot call web api 2 post method with int parameter in URL in Unit Test using Http server

Please ignore the spelling mistake, I cannot copy code so I have typed the whole thing and changed name of controller and method.
WEB API 2
Controller:
// Controller name is Test
public HttpResponseMessage Method1(int param1) // Post method
{
// return string
}
If I create an object of controller in test case then it is working fine. But if I want to test in localhost using following code:
Unit Test:
public void Method1Test()
{
HttpResponseMessage response;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using(var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test?param1=1");
request.Content = new ObjectContent<int>(param1, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
Now, my test case is failing. I used the same code in different project and it worked. May be it is the way I am trying to call Post method. Is this the right way to call post method with Int parameter in URL?
In help page, under API column it shows:
POST api/test/param1={param1}
Also I have put some stop point in actual service I am cursor is not stopping at that point. Why?
If I want to call the same service from browser, what URL should I pass? Is it -
http://localhost:5022/api/test?param1=1
Or something else?
I figured it out. Following is the correct unit test method but this has some extra information which I have not provided earlier i.e., passing object as an input for the service.
private void Method1Test(ObjectClass obj)
{
HttpResponseMessage response = null;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using (var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test/1");
request.Content = new ObjectContent<ObjectClass>(obj, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
So the correct URL that I was looking for was
http://localhost:5022/api/test/1
Sorry, It took long to post this answer. This method is working like a charm for more then 2 years.

Servlet Filter as Security Proxy for Web Services

Good time.
Suppose there are 8 web-services in the one application. 5 of them require authorization (a client must to provide a JSESSIONID cookie and a corresponding session must not be invalidated), other 3 can be called without the jsessionid cookie. My naive solution is to write a servlet filter which intercepts requests and retrieve their pathInfos (all the services have the same url structure: /service/serviceSuffix). There is a enum which contains the serviceSuffix of each web service that requires authorization. When the request is retrieved the pathInfo is collected; if this pathInfo is contained in the enum and there is the corresponding valid session the request is sent ahead to the filter chain. Otherwise, an error is sent back to a client. After a while I've realized that it is needed to add the possibility to retrieve the wsdl and xsds for the concrete service. So that, two more check were added.
public class SecurityFilter implements Filter {
public static final String WSDL = "wsdl";
public static final String XSD = "xsd=";
/**
* Wittingly left empty
*/
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse)response;
String pathInfo = servletRequest.getPathInfo();
String queryString = servletRequest.getQueryString();
if (pathInfo != null && SecureWebServices.contains(pathInfo)) {
if (queryString != null && (queryString.equals(WSDL) || queryString.startsWith(XSD))) {
// wsdl or xsd is requested
chain.doFilter(request, response);
} else {
// a web service's method is called
HttpSession requestSession = servletRequest.getSession(false);
if (requestSession != null) { // the session is valid
chain.doFilter(request, response);
} else {
servletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
} else {
chain.doFilter(request, response);
}
}
/**
* Wittingly left empty
*/
public void destroy() {}
}
It seems that it is not very secure, because if the request's pathInfo is not in the enum, this request is passed on (just in case of some unexpected system calls).
Could you, please, suggest what to do, how to increase the security level. I want to build a configurable system (that is why I have the enum. It is possible just to add a path there to secure the web service and it is not required to duplicate the security code in the each web service). How to increase
Maybe I do not understand but.
jsessionid has nothink to do with security. you simply just get it.
Next I am not sure if you want authentication or authorization. The code as provided will not provide you with security features.
I suppose you are interested in authentication anyway. Security logic can be provided with standard web container features. Just send in authentication data in the header of request and you are done. web container can be configured to secure only selected resources (urls)