Intercept routes without tracing - apache-camel

The application I'm working on is a middleware app that allows routing among tons of applications (mostly SOAP services).
We encountered saturation because of the automatic logs generated by Camel.
The log volume was reduced with the new interceptors. However, if a service is called inside a current route, all I got is the Request Body from the SendToEndpoint interceptor.
Given that all service calls in the application was made that way, I can not change the current routes.
Old interceptors:
getContext().setTracing(true); // <--- trace every step of all routes
interceptFrom().to("log:example");
configureRoutes() {
// route logic
}
New interceptors:
getContext().setTracing(false);
interceptFrom("cxf:*").to("log:example");
interceptSendToEndpoint("cxf:*").to("log:example");
configureRoutes() {
// route logic
}
Example of a route :
from("scheduler endpoint")
.to("DAO method to find the case from database")
.process(//First processor to call the SOAP service)
.to("SOAP endpoint")
.convertBodyTo(SOAP ResponseBody.class) <-- convert the MessageContentsList to SOAP response body generated from the WSDL
.process(//Second processor to check if the response code is OK in the SOAP response body);
How can I implement an interceptor that allows to log also the SOAP response body ?
Thank you for your help.

I dislike to use interceptors to this porpoise, I suggest you to use the EventNotifier interface, you just need to declare it as a bean in camel context and override the notify method.
See: https://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/spi/EventNotifier.html
Here is an usage example: http://camel.apache.org/eventnotifier-to-log-details-about-all-sent-exchanges.html
Note: Camel has some events that you can uss like: CamelContextCreated, ExchangeCreatedEvent, ExchangeSendingEvent, ExchangeSentEvent, ExchangeCompletedEvent, ExchangeFailedEvent, etc.

Related

How to intercept requests from external handlers using Cypress?

Does anyone know how a request that launches an external handler (such as an email app) can be intercepted to obtain the Request URL?
The in-browser request that launches the external app looks like this:
Request URL: mailto:example#example.com?Subject=Test&Body=test
Referrer Policy: strict-origin-when-cross-origin
I'm trying to do as follows and it doesn't work:
cy.intercept('mailto:**').as('mailto')
cy.get('#submitButton').click()
cy.wait('#mailto').its('request.url').should('contain.text', 'Subject')
It fails on cy.wait('#mailto') and the Routes from Cypress's interface presents the following (that it doesn't catch the request):
Method
Route Matcher
Stubbed
Alias
#
*
mailto:**
No
mailto
-
Also, already tried to use different Cypress versions: 6.4.0, 6.9.1 and 8.2.0.
Hope someone can help. Thanks in advance.
It turns out that mailto: doesn't seem to be a request, it's more like a link inside an <a> of your HTML...
A request usually has a method (GET, POST, DELETE) and a URL, and then you can intercept using cy.intercept.
It turns out that when you click on the link that contains Mailto a request is not created, this link serves to open your email client, so you need to create an assertion for this link in another way.
cy.intercept('POST', '/createuser*').as('createUser')
cy.wait('#createUser')
This is the way I use to intercept a request, making the test wait for the response before proceeding, it is for requests that your frontend makes to your backend server or third party services.

Appending some info to each requset in REST API

I have an angular application. From frontend I can set some value. This value is something like config, which can be changed.
It is simple string variable. How to attach this config to each REST request ?
I ask mainly about approach.
Maybe pass it via headers is good idea ?
For angular 1.x, write an Interceptor:
For purposes of global error handling, authentication, or any kind of
synchronous or asynchronous pre-processing of request or
postprocessing of responses, it is desirable to be able to intercept
requests before they are handed to the server and responses before
they are handed over to the application code that initiated these
requests
For angular 2.x / 4.x, RequestOptions should be the key to solve your problem. Set base url for angular 2 http requests
I'm using angular2, my solution is create a Service and inject "Http" dependency, then write two methods "get", "post", these methods add an entry to header before calling "Http", in other component / service, I just inject this Service class, then call its "get" or "post".
Your code should be somewhat like this If your working in angular 1.3 or less
The data should be sent as body data to server
var basecall = Restangular.all('url');
bascall.post($scope.config).then(function(data){
})

Integrating with web services in Electron

I'm brand new to Electron and I'm about to start development of a desktop application using Electron/AngularJS. The desktop application is just going to be GUI that interacts with a backend server via a RESTful web service and web sockets.
Now my question: what is the best way in Electron to issue HTTP requests to the web service and update the UI? In normal web apps I'd just interact with the web service directly using something like Angular's $http service. However, I'm unable to do this in Electron because the same-origin policy will block the request (from what I understand the renderer runs in the file:// origin so I cannot communicate with mysite.com).
I've come up with a couple of potential solutions, but they don't seem ideal:
Disable the same-origin policy issue by setting the BrowserWindow preference 'web-security' to false. This does not seem like a good idea because if I have any sort of cross-site scripting in my UI code, then the attacker can accessing any files on my box.
Proxy all my HTTP requests through the IPC interface. The main process can then make the HTTP requests without the restrictions of the same-origin policy. This just seems like overkill, though.
Am I missing a simpler solution?
The view html file is loaded in electron via file protocol and ajax does not work in file protocol. In my case I setup an IPC event emitter in the html and an IPC event handler in the main process. Once I needed to make any http call I used the event emitter and then made the http request from the main process. After the request completed I made another IPC event from the main process and handled it in the html. I don't know if its the most elegant way but it worked in my case.
// sample code in the html
<script>
const ipc = require("electron").ipcRenderer;
function sendAjaxCall(params){
// handle the params
// and make a ipc event to the main process
ipc.send("call-AJAX", params)
}
// call the sendAjaxCall function somewhere with proper params
ipc.on("complete-AJAX", function(evt, arg){
// process your args and handle the return data
})
</script>
// sample code in the main js file
const ipc = require("electron").ipcMain;
const request = require("request"); // request is not required, but I found it quite fascinating...
ipc.on("call-AJAX", function(evt, arg){
// process the args and make the ajax call
request("http://some-url.com/some/endpoint/", function(e, resp, body){
// handle the response
// send ipc event to renderer process
ipc.send("complete-AJAX", resp)
})
})
Warning This code above is just some boilerplate code to get you the basic idea. I found a great article on medium Electron’s IPC Modules and How to Use Them where you can get some basic understanding of IPC.
Further Resources-
ipcMain on Electronjs.org
ipcRenderer on Electronjs.org
Request on npmjs.com
from what I understand the renderer runs in the file:// origin so I cannot communicate with mysite.com
I'm pretty sure this is not the case, file:// can communicate with any origin
As an alternative option consider enabling CORS on the server and make CORS requiests from the client.

Restlet CorsFilter with ChallengeAuthenticator

I'm building a RESTful API with the Restlet framework and need it to work with cross domain calls (CORS) as well as basic authentication.
At the moment I'm using the CorsFilter which does the job of making my webservice support CORS requests. But, when I try to use this with a simple ChallengeAuthenticator with HTTP Basic Authentication it won't work as I want it to (from a web site).
When I access the webservice directly via Chrome it works as intended, but when I try it in a small web application written in angularjs (jquery/javascript) and try to access the webservice it does not.
Basically what happens is that when a OPTIONS request is sent to my webservice it will not respond with the headers: 'Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials', etc. as it should. Instead it is sending a respond with HTTP status code 401 saying that the authentication failed.. Is this because the authenticator is overriding the CorsFilter somehow?
My createInboundRoot method can be seen below.
#Override
public Restlet createInboundRoot() {
ChallengeAuthenticator authenticator = createAuthenticator();
RoleAuthorizer authorizer = createRoleAuthorizer();
Router router = new Router(getContext());
router.attach("/items", ItemsServerResource.class);
router.attach("/items/", ItemsServerResource.class);
Router baseRouter = new Router(getContext());
authorizer.setNext(ItemServerResource.class);
authenticator.setNext(baseRouter);
baseRouter.attach("/items/{itemID}", authorizer);
baseRouter.attach("", router);
// router.attach("/items/{itemID}", ItemServerResource.class);
CorsFilter corsFilter = new CorsFilter(getContext());
corsFilter.setNext(authenticator);
corsFilter.setAllowedOrigins(new HashSet(Arrays.asList("*")));
corsFilter.setAllowedCredentials(true);
return corsFilter;
}
(The authorizer and authenticator code is taken from the "official" restlet guide for authorization and authentication)
I've tried alot of changes to my code but none which given me any luck. But I noticed that when setting the argument "optional" in ChallengeAuthenticator to true (which "Indicates if the authentication success is optional") the CorsFilter does its job, but obviously the ChallengeAuthenticator does not care about authenticating the client and lets anything use the protected resources..
Has anyone had a similar problem? Or have you solved this (CORS + Authentication in Restlet) in any other way?
Thanks in advance!
I think that it's a bug of the Restlet CORS filter. As a matter of fact, the filter uses the method afterHandle to set the CORS headers. See the source code: https://github.com/restlet/restlet-framework-java/blob/4e8f0414b4f5ea733fcc30dd19944fd1e104bf74/modules/org.restlet/src/org/restlet/engine/application/CorsFilter.java#L119.
This means that the CORS processing is done after executing the whole processing chain (authentication, ...). So if your authentication failed, you will have a status code 401. It's actually the case since CORS preflighted requests don't send authentication hints.
For more details about using CORS with Restlet, you could have a look at this link: https://templth.wordpress.com/2014/11/12/understanding-and-using-cors/. This can provide you a workaround until this bug was fixed in Restlet itself.
I opened an issue in Github for your problem: https://github.com/restlet/restlet-framework-java/issues/1019.
Hope it helps,
Thierry
The CorsService (in 2.3.1 coming tomorrow) contains also a skippingResourceForCorsOptions property, that answers directly the Options request without transmitting the request to the underlying filters and server resources.

Handling SAML Redirects on AJAX Requests

I have several AngularJS apps all using Spring/Java and SAML 2.0 for SSO (leveraging the Spring Security SAML extension). My SSO id provider is OpenAM and everything is working pretty well. However, I am running into a situation when a user does a global logout from within one application but has other tabs open. Since these are single page web apps, a lot of functionality may still be usable in the orphaned tabs UNTIL, the user does something to invoke an ajax request. Of course, these AJAX requests get intercepted by the Spring Security SAML filters and triggers an authentication attempt via a REDIRECT to the OpenAM login URL. Of course, this wreaks havoc in the browser since redirects to another domain aren't allowed on AJAX requests. Furthermore, I can't really do anything with Angular's $http interceptors as the requests are 'canceled' and no quality information is available in the $http error callback function (such as a convenient 401/403 status code). All I know is that the request failed.
I don't want to assume that all bad $http requests are due to authentication problems (and do a $window.location.reload()) as there could be legitimate reasons for failure. My preference is to suppress the Spring Security redirect (to OpenAM login page) for ajax requests and, instead, send back a 401/403 status code. This would allow me to handle the error in the $http interceptor and do a full page load if it is an authentication failure, thus elegantly redirecting to the login page as if they were going to the site for the first time.
Any ideas for how to accomplish this?
The bean responsible for initialization of authentication and decision to return an HTTP error, perform a redirect, ... is an instance of AuthenticationEntryPoint. To change its behavior you can either:
customize the current SAMLEntryPoint (extend the commence method) and override the default behavior in case request is an AJAX call from Angular, so it returns an HTTP error instead of performing redirect to IDP
or define another security:http element in your Spring context (before the current one) which only covers your AJAX requests (e.g. with attribute pattern="/api/**") and uses an entry point which behaves in the way you want (see Http403ForbiddenEntryPoint)
Referring to a possible implementation of Vladimir's first bullet - taken from https://www.jasha.eu/blogposts/2015/10/saml-authentication-angularjs-spring-security.html
public class XhrSamlEntryPoint extends SAMLEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
if (isXmlHttpRequest(request) && e instanceof InsufficientAuthenticationException) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
return;
}
super.commence(request, response, e);
}
private boolean isXmlHttpRequest(HttpServletRequest request) {
return "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"));
}
}
Keep in mind that X-Requested-With is not a mandatory header so the detection is not bullet-proof according to this answer. In my case since the backend was used with a SPA frontend, I removed the check of ajax call altogether.

Resources