I have 2 spring based applications both of them uses spring-sleuth.
Application-1:
AmazonSNS snsPublisher;
snsPublisher.publish(message)
I would like to add MDC context here somehow, so that application-2 can use the same context. Is there any integration that is provided to achieve this ?
Application-2:
#SqsListener
public void process(String message, #Headers Map<String, MessageAttributeValue> sqsHeaders)
When I receive the MDC context(traceId) set by other application in headers, then I need an integration which can add that same MDC context in application-2 as well. So that, when I look at logs I will have a whole picture of what has happened with that request combining both of these applications.
Related
I am trying to add a grpc protofile to my swagger-ui. I am consuming a grpc webservice which needs a protofile as input. The input to my spring boot restful webservice needs to have that same grpc structure as its interface. I recevied a jar from the individual that made the protofile and imported it to my webserivce. When I try to add the #ResponseBody tag around the object from the protofile jar, my app hangs on this in the console at startup:
s.d.s.w.s.ApiListingReferenceScanner : Scanning for api listing references
Thanks,
Brian
Never return entity objects in controller method.
in my case. my Controller methods takes this parameter.
"#AuthenticationPrincipal UserSession userSession"
when i exlude UserSession object swagger back to normal.
There were 2 way to do that
first is "#ApiIgnore #AuthenticationPrincipal UserSession userSession"
second is in swaggerConfig class
private Class[] clazz = {UserSession.class};
Docket().ignoredParameterTypes(clazz)
Incase someone needs a solution, what I did was as a work around for now.
in my service's code (response is a String)
return JsonFormat.printer().print(myProtoObject);
in my client's code:
Builder b = ProtoObject.newBuilder();
JsonFormat.parser().merge(result.getBody(), b);
ProtoObject protoObject = b.build();
Changing the Order of the Spring Security WebFilter
I have an API Gateway implemented using Spring Cloud Gateway that uses Spring Security. Spring Security for WebFlux is implemented as a WebFilter right at the beginning of the filter chain. So after successful authentication the request would be forwarded to Spring Cloud Gateway's RoutePredicateHandlerMapping, which would try to deduce the destination based on the URL pattern, and then it would go to a FilteringWebHandler to execute the other filters of Spring Cloud Gateway.
My problem is the following: I have implemented a customized authentication algorithm which uses query string and header variables as credentials for authentication according to the requirements of the project, an this is working without any problem. The problem occurred when we needed to add a small customization for the authentication algorithm that is path independent. When the request reaches the WebFilter of Spring Security, pattern matching is not yet done so I do not know which application does it point to, for example:
app1:
-Path: /app1/**
app2:
-Path: /app2/**
Which means that instead of having authentication -> route mapping -> filtering web handler I should do route mapping -> authentication -> filtering web handler. Not that these three components are not similar, one of them is a filter another is a mapper and the last one is web handler. Now I know how to customize them but the problem is that I do not know how to intercept the Netty server building process in order to change the order of these operations. I need to wait for the building process to end and alter the content of the server before it starts. How can I do that?
EDIT: here is the final solution:
So here is how I did it:
Goal: removing the WebFilter of Spring Security from the default HttpHandler, and inserting it between RoutePredicateRouteMapping and the FilteringWebHandler of Spring Cloud Gateway
Why: Because I need to know the Application ID while carrying on my customized authentication process. This Application ID is attached to the request by the RoutePredicateRouteMapping by matching the request's URL to a predefined list.
How did I do it:
1- Removing the WebFilter of Spring Security
I created an HttpHandler bean that invokes the default WebHttpHandlerBuilder and then customize the filters. As a bonus, I removed unneeded filters in order to increase the performance of my API Gateway
#Bean
public HttpHandler httpHandler() {
WebHttpHandlerBuilder webHttpHandlerBuilder = WebHttpHandlerBuilder.applicationContext(this.applicationContext);
MyAuthenticationHandlerAdapter myAuthenticationHandlerAdapter = this.applicationContext.getBean(MY_AUTHENTICATED_HANDLER_BEAN_NAME, MyAuthenticationHandlerAdapter.class);
webHttpHandlerBuilder
.filters(filters ->
myAuthenticationHandlerAdapter.setSecurityFilter(
Collections.singletonList(filters.stream().filter(f -> f instanceof WebFilterChainProxy).map(f -> (WebFilterChainProxy) f).findFirst().orElse(null))
)
);
return webHttpHandlerBuilder.filters(filters -> filters
.removeIf(f -> f instanceof WebFilterChainProxy || f instanceof WeightCalculatorWebFilter || f instanceof OrderedHiddenHttpMethodFilter))
.build();
}
2- Wrapping Spring Cloud Gateway's FilteringWebHandler with Spring Web's FilteringWebHandler with the added WebFilter
I created my own HandlerAdapter which would match against Spring Cloud Gateway's FilteringWebHandler and wrap it with Spring Web's FilteringWebHandler plus the security filter I extracted in the first step
#Bean
public MyAuthenticationHandlerAdapter myAuthenticationHandlerAdapter() {
return new MyAuthenticationHandlerAdapter();
}
public class MyAuthenticationHandlerAdapter implements HandlerAdapter {
#Setter
private List<WebFilter> securityFilter = new ArrayList<>();
#Override
public boolean supports(Object handler) {
return handler instanceof FilteringWebHandler;
}
#Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
org.springframework.web.server.handler.FilteringWebHandler filteringWebHandler = new org.springframework.web.server.handler.FilteringWebHandler((WebHandler) handler, securityFilter);
Mono<Void> mono = filteringWebHandler.handle(exchange);
return mono.then(Mono.empty());
}
}
This way I could achieve better performance with highly customized HttpHandler pipeline that I suppose to be future-proof
END EDIT
Spring Security for WebFlux is implemented as a WebFilter which is executed almost as soon as a request is received. I have implemented custom authentication converter and authentication manager which would extract some variables from the header and URL and use them for authentication. This is working without any problem.
Now I needed to add another variable taken from RoutePredicateRouteMapping before authentication is done. What I want exactly is to remove the WebFilter (called WebFilterChainProxy) from its current position and put it between the RoutePredicateRouteMapping and the FilteringWeHandler.
Here is how the default process goes:
ChannelOperations calls ReactorHttpHandlerAdapter which calls HttpWebHandlerAdapter, ExceptionHandlingWebHandler, and then org.springframework.web.server.handler.FilterWebHandler.
This WebHandler would invoke its filters and then call the DispatchHandler. One of those filters is the WebFilterChainProxy that does the authentication for Spring Security. So first step is removing the filter from here.
Now the DispatchHandler which is called after the filters would invoke RoutePredicateHandlerMapping, which would analyze the routes and give me the route ID that I need, and then it would call the org.springframework.cloud.gateway.handler.FilteringHandler (this is not the same FilteringHandler above), and that in turn would call the other filters of the Spring Cloud Gateway. What I want here is to invoke the filter after RoutePredicatehandlerMapping and before org.springframework.cloud.gateway.handler.FilteringHandler.
What I ended doing was the following:
I created and WebHttpHandlerBuilder that would remove WebFilterChainProxy and pass it as a parameter to a customized DispatcherHandler. Now that the filter is removed the request would pass the first layers without requiring authentication. In my customized DispatcherHandler I would invoke the RoutePredicateHandlerMapping and then pass the exchange variable to the WebFilterChainProxy to do the authentication before passing it to the org.springframework.cloud.gateway.handler.FilteringHandler, which worked perfectly!
I still think that I'm over engineering it and I hope that there is a way to do it using annotations and configuration beans instead of all these customized classes (WebHttpHandlerBuilder and DispatcherHandler).
You should probably implement that security filter as a proper GatewayFilter, since only those are aware of the other GatewayFilter instances and can be ordered accordingly. In your case, you probably want to order it after the routing one.
Also, please don't cross-post, the Spring team is actively monitoring StackOverflow.
I had a similar problem. The accepted solution, while interesting, was a bit drastic for me. I was able to make it work simply by adding my custom filter before SecurityWebFiltersOrder.AUTHENTICATION in the security configuration. This is similar to what I've done with success in a regular Spring mvc application.
Here's an example using oauth authentication. tokenIntrospector is my custom introspector, and requestInitializationFilter is the filter that grabs the tenant id and stashes it in the context.
#AllArgsConstructor
#Configuration
#EnableWebFluxSecurity
public class WebApiGatewaySecurityConfiguration {
private final GatewayTokenIntrospector tokenIntrospector;
private final GatewayRequestInitializationFilter requestInitializationFilter;
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
// #formatter:off
http
.formLogin().disable()
.csrf().disable()
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer.opaqueToken(c -> c.introspector(tokenIntrospector)))
.addFilterBefore(requestInitializationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
return http.build();
// #formatter:on
}
}
I'm trying to read a message from RabbitMQ using spring-amqp and convert it to my domain object.
I've successfully configured it to receive a json message and map it to my domain object using the Jackson2JsonMessageConverter class.
Now, I'm trying to use the ContentTypeDelegatingMessageConverter and add the ability to receive XML (in addition to JSON).
But, unfortunately, I'm having a hard time finding either a built-in message converter that handles XML or documentation on how to configure one of the built-in converters to handle XML.
The documentation on how to handle XML using spring-amqp seems pretty sparse. So, I'd appreciate a code sample that adds to mine below (please see TODO):
#Bean
MessageConverter messageConverter() {
ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter();
Jackson2JsonMessageConverter jsonMessageConverter = new Jackson2JsonMessageConverter();
messageConverter.addDelegate("application/json", jsonMessageConverter);
// TODO: messageConverter.addDelegate("application/xml", xxx);
return messageConverter;
}
Thanks!!
Use a MarshallingMessageConverter configured with a Spring OXM marshaller/unmarshaller - see Spring Framework OXM documentation for information about the various marshallers/unmarshallers using a number of different technologies.
I am attempting to create some UI tests using SpecsFor MVC, I am coming at this from a new user's point of view in terms of testing so could be easily missing something obvious.
The site I'm testing against already uses it's own test DB so I do not need to create one. when I build and debug normally on this site it also starts up a couple of WCF projects which we use for service layer interactions. Presumably I'll need to start these in the specs config but have not got that far yet.
I've followed the documentation and have created this method:
protected override void AfterConfigurationApplied()
{
var config = new SpecsForMvcConfig();
config.UseIISExpress()
.With(Project.Named("TestSite"))
.UsePort(55555)
.CleanupPublishedFiles()
.UseMSBuildExecutableAt(#"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe");
config.BuildRoutesUsing(MvcApplication.RegisterRoutes);
config.UseBrowser(BrowserDriver.Chrome);
_host = new SpecsForIntegrationHost(config);
_host.Start();
}
The routing of the site is set in the Global.asax hence the setting in the above method.
I also have this very basic test in place to just see if I can get it working:
protected override void When()
{
SUT.NavigateTo<HomeController>(u => u.Index());
SUT.FindLinkTo<HomeController>(u => u.About())
.Click();
}
When I debug the tests it successfully starts Chrome but hangs for ages and eventually fails with this error:
OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:49924/session/bd15d6a15395b4ca204437c340639501/element timed out after 60 seconds.
I'm not sure where that port number or session etc are coming from.
If I'm running my web project normally (outside of this whole testing project) I see a URL like this:
https://localhost:55555
I would have thought I'd see something similar for these tests cases? It doesn't really matter in any case because they're not working.
Am I missing some element of the config? Do I need to set up the WCF layer to run as well?
I am trying to get spring security context to propagate through an spring integration async message flow, but have found that even though I added SecurityContextPropagationChannelInterceptor the security context always ends up null in my message handler.
#Bean
#GlobalChannelInterceptor(patterns = {"*"})
public ChannelInterceptor securityContextPropagationInterceptor()
{
return new SecurityContextPropagationChannelInterceptor();
}
I initiate my flow from a service that has a populated security context by making a call to my gateway interface:
#MessagingGateway
public interface AssignmentsService
{
#Gateway(requestChannel = "applyAssignmentsFlow.input")
ListenableFuture<AssignmentResult> applyAssignments( AssignmentRequest assignmentRequest );
}
On further debugging I have found that the GatewayProxyFactoryBean creates a new thread when initiating my flow, but does not propagate the security context.
I have searched but have been unable to find out how to configure this to propagate the security context.
That's pretty interesting task. Indeed :) !
But anyway you can do it like this:
#Bean
public AsyncTaskExecutor securityContextExecutor() {
return new DelegatingSecurityContextAsyncTaskExecutor(new SimpleAsyncTaskExecutor());
}
...
#MessagingGateway(asyncExecutor = "securityContextExecutor")
public interface AssignmentsService
The main trick here is from Spring Security and its concurrency utils, where we should use TaskExecutor wrappers to pick up the current SecurityContext and propagate it into newly spawned Thread.
There is nothing about Spring Integration, though - just the proper way to work with Security.
Will add such a trick into Reference Manual soon.
Pull request on the matter: https://github.com/spring-projects/spring-integration/pull/2015