How to call security setup when message received using Spring Integration - spring-integration

I currently am using Spring Integration to get messages off of a queue and send them to a service using a service activator. My issue is that the service I am calling requires a security context to be in place for the current thread. This can be setup by calling a no-argument method, handleAuthentication(), of another bean. I am wondering what the best way is to call this whenever a new message is received, prior to calling the service activator service? I was originally thinking I would chain together two service activators, with the first one calling handleAuthentication(), but this seems incorrect as handleAuthentication() does not require any information from the actual message.

Yes, your assumption about the security handling is correct. It is really just a side-effect aspect which should not be tied with the business logic.
Therefore we should use something which allows us to follow with the same behavior in the program. It is called as an Aspect in the programming as well.
For this purpose Spring Integration suggests a hook like MessageChannelInterceptor, where you can implement your handleAuthentication() exactly in the preReceive() callback, according to your explanation.
Another trick can be achieved with the <request-handler-advice-chain> and MethodInterceptor implementation which should populate the SecurityContext into the current thread just before target service invocation.

Related

Sleuth, Spring Integration and ThreadPoolExecutor: how to have one span per spawned thread?

There is an ExecutorChannel in my integration flow that will spawn one thread per message. The delegation chain looks like this:
ExecutorChannel (Spring Integration) -> BlockingExecutor (my own) -> ThreadPoolExecutor (vanilla Java)
Everything that happens in the Spring Integration part is of no interest to me. Ideally, I'd like turn off Spring Integration tracing with spring.sleuth.integration.enabled: false and simply annotate the method that will eventually called by the Spring Integration part with #NewSpan.
But when I disable spring integration, the span will appear only once: created by the main thread.
I've tried setting spring.sleuth.integration.enabled: true and excluding all but the relevant outbound channel via spring.sleuth.integration.patterns, but it's the same: only the main thread's span will appear in Zipkin.
Am I going at this from the wrong angle? What would be the best way of doing this?
The tracing propagation is done in Sleuth by the TracingChannelInterceptor. So, if you disable it, this one is not going to be applied to channels. If you see issues, then you need to apply it manually on the channel which are switching threads.
You can do that manually adding an interceptor to the channel directly or via #GlobalChannelInterceptor with respective pattern matching:
https://docs.spring.io/spring-integration/docs/current/reference/html/core.html#global-channel-configuration-interceptors

How to use ChannelInterceptor to stop the execution flow in the Spring integration

There is Spring integration flow. This has to be stopped manually by the user while being run and need to use ChannelInterceptor to stop the execution. This is xml based configuration.
To stop the flow there is just enough to call stop() on the endpoint which is a beginning for the flow. Autowire an AbstractEndpoint for the specific id and call its stop(). It really doesn't matter if you are going to do that in the ChannelInterceptor or some other service.
There is also a common patterns called Control Bus, where one of the commands to send could be the mentioned stop() operation: https://docs.spring.io/spring-integration/docs/current/reference/html/system-management.html#control-bus

how to use spring webclient properly in the tenant context

I am using the Spring WebClient (org.springframework.web.reactive.function.client.WebClient) in order to implement some non-blocking behaviour.
Mono<ClientResponse> clientResponse =
webClient
.get(...).exchange();
clientResponse.subscribe((response) -> {
//--- unfortunately my tenant context is lost here !!! Someone knows the right solution?
});
However my tenant-context gets lost once the response arrives (of course, we are in a new thread).
Here is the documentation of how to implement common asynchronous tasks within the tenant-context: https://sap.github.io/cloud-sdk/docs/java/features/multi-tenancy/multi-tenancy-thread-context/
However, I couldn't find the recommended way how to remain the tenant-context using Spring webflux (using the WebClient).
Edit: The SAP Cloud SDK destroys a ThreadContext at the end of an operation. This is done to prevent it from leaking e.g. when the thread is re-used.
If:
the context is passed to an asynchronous operation
but the "parent" operation is done before the asynchronous operation starts
the ThreadContext will not be available in the asynchronous operation. That is what is happening when using the WebClient.
This is not true for custom properties, the SDK does not clear them. But that also means that you have to clear them yourself to ensure they don't leak when the thread is being re-used.
I'd recommend not to use the multi tenancy features of the SDK in such cases. Still, I'll leave my below answer in for context.
You can transfer the SAP Cloud SDK's ThreadContext to any new Thread if and only if you have control:
Before the new Thread is created
The operation that will be run asynchronously that requires the context
Edit: The parent thread (context) still exists
I am not too familiar with WebFlux, but I'll assume that:
clientResponse.subscribe runs in the parent Thread
And the lambda is executed in the asynchronous Thread
Given that, the following should transfer the ThreadContext to be present in the lambda:
ThreadContextExecutor executor = new ThreadContextExecutor();
clientResponse.subscribe((response) ->
executor.execute(() ->
{
// your code goes here, the ThreadContext should be available
}
)
);
You would have to do this at every point where an operation is running in a new Thread. As Artem pointed out, currently there is no feature in the SDK for this that would achieve the same automagically.
I think it is also possible to define a custom ExecutorService that Spring will use to create and run new Threads. In a custom executor you could encapsulate this wrapping logic once for all operations.
The SAP Cloud SDK APIs support Spring Boot and currently don't support Spring Webflux out of the box. You'll probably see all sorts of errors if using the SDK APIs with reactive Spring development. On the other hand, as Matthias showed workarounds might be possible for certain use-cases.
We consider adding Spring WebFlux support in the future. It probably won't happen this year (in 2021).

Is it possible to make a Poller (or PollableMessageSource) to poll messages as List?

Following the example found in GitHub https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-pubsub-polling-binder-sample regarding polling messages from a PubSub subscription, I was wondering...
Is it possible to make a PollableMessageSource retrieve List<Message<?>> instead of a single message per poll?
I've seen the #Poller notation only being used in Source typed objects, never in Processor or Sink. Is it possible to use in such context when for example using #StreamListener or with a functional approach?
The PollableMessageSource binding and Source stream applications are fully based on the Poller and MessageSource abstraction from Spring Integration where its contract is to produce a single message to the channel configured. The point of the messaging is really to process a single message not affecting others. The failure for one message doesn't mean to fail others in the flow.
On the other hand you probably mean GCP Pub/Sub messages to be produced as a list in the Spring message payload. That is really possible, but via some custom code from Pub/Sub consumer and MessageSource impl. Although I would think twice to expect some batched from the source. Probably you may utilize an aggregator to build some small windows if your further logic is about processing as list. But again: it is going to be a single Spring message.
May be better to start thinking about a reactive function implementation where you indeed can expect a Flux<Message<?>> as an input and Spring Cloud Stream framework will take care for you how to emit the data from Pub/Sub into the reactive stream you expect.
See more info in docs: https://docs.spring.io/spring-cloud-stream/docs/3.1.0/reference/html/spring-cloud-stream.html#_reactive_functions_support

Exception handling in xml based spring integration

How to publish exception in error-channel whenever we encounter any exception in any of the route. We dont want to catch exception manually. It should automatically routed to error-channel?
No, it can't go automatically to the error-channel. That's not how plain Java works. So, if you call some java code you expect an exception from there and you definitely use a try...catch construction.
The error-channel makes sense only in the processes not started by end-users, some active processes like task executors and schedulers. For this purpose we indeed provide an error-channel hook do not let downstream error to disappear.
Another way to do a-la try...catch, but still send to the error-channel can be done via Messaging Gateway: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#gateway-error-handling. This way the Framework wraps the whole flow to the try...catch and sends an ErrorMessage to the configured errorChannel.
Also for per-service purpose we provide an ExpressionEvaluatingRequestHandlerAdvice with its own in-scope failureChannel: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints-chapter.html#expression-advice

Resources