Java Spring Boot Webflux cors blocked - java

I am trying to build out an Angular & Spring Boot app with Webflux, and instead of starting by getting bogged down by a full CRUD tutorial with entities and databases I thought I'd start by just seeing if I could get the client to display a string returned by the server, as spring boot's documentation teaches here. To that end, I have the following code:
//Angular client
private currencyGreetingUrl: string;
constructor(private http: HttpClient) {
this.currencyGreetingUrl = 'http://localhost:8080/currency';
}
public getCurrencyGreeting(): Observable<string> {
return this.http.get<string>(this.currencyGreetingUrl);
}
//Spring Boot Web Client
#CrossOrigin(origins = "http://localhost:4200")
public class CurrencyWebClient {
private WebClient client = WebClient.create("http://localhost:8080");
private Mono<ClientResponse> result = client.get()
.uri("/currency")
.accept(MediaType.TEXT_PLAIN)
.exchange();
public String getResult() {
return ">> result = " + result.flatMap(res -> res.bodyToMono(String.class)).block();
}
}
//Spring boot handler
#Component
public class CurrencyHandler {
public Mono<ServerResponse> currency(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromValue("Hello, Currency On The Go!"));
}
}
//Spring Boot router
#Configuration
public class CurrencyRouter {
#Bean
public RouterFunction<ServerResponse> route(CurrencyHandler currencyHandler) {
return RouterFunctions
.route(RequestPredicates.GET("/currency").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), currencyHandler::currency);
}
}
However, I get this error when running the client and server Access to XMLHttpRequest at 'http://localhost:8080/currency' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I am new to Spring Boot and have been looking around for advice, but I've generally found solutions that involve configurations, controller classes, and other more built out artifacts than what I currently have. How could I get this to work? I appreciate any help.

You have decided to use functional endpoints and you are not using spring security of what i can tell from your tags which means all other answers provided here are faulty.
When using functional endpoints you have to be aware that you have opted out of using the traditional annotation based classes. Which means you loose a lot of the free functionality provided by the spring framework
Functional endpoints are more "low level". So the responsibility falls on you the developer to handle CORS.
If you are a beginner on Spring and webflux i would not pick this route.
The documentation states in the CORS chapter in the official webflux documentation:
You can apply CORS support through the built-in CorsWebFilter, which
is a good fit with functional endpoints.
They even provide an implementation of a standard CORS filter that you can customize to your needs.
#Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// Possibly...
// config.applyPermitDefaultValues()
config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
There is 100s of webpages on the internet that explain CORS and it is the most common question asked in the spring-boot, spring-security tag. I suggest you read up on CORS (which you should of done before asking here).
I highly suggest you start reading here:
Mozilla CORS

Have you configured cors properly?
If not try following:
https://stackoverflow.com/a/67605427/9295125
Please also read the second answer as the posted answer misses one line.

For my purposes when using Webflux with a browser-based front-end where I need to test quickly, I use a CORS-enabling Chrome extension to test quickly. This is obviously not great for production.
If you are in a pure microservice / backend communication situation, you may just need to go with Spring's intended workflow. In my experience, Spring Webflux has some powerful outcomes but finicky setup. Those configuration classes that you mentioned but are avoiding, or annotations or DSL-based solutions for Kotlin are, unfortunately for now, the intended way. In my experience they do work, and once you have them set up it's a matter of making a quick github-ready template for other microservices (I was building Microservices with Spring and Kotlin at the time).
EDIT: I will also just add that those configurations and classes you're avoiding are worth your time, even a morning of your time spent on those will pave the way for a lot of productivity. Webflux is great (and I've used it both with Kotlin and Java) but there are some unavoidable gotchas and configuration differences when you jump to asynchronous / reactive webflux land. The joy in the config comes when you realize you did things right and it's your DB driver that's freaking out when you can push so many requests :) :) :)

Indeed I did need to use the CorsWebFilter. However, after reading a bit on Spring Boot and its Dependency Injection system, and looking at different tangentially related cors implementation in Spring Boot projects that didn't use functional endpoints, I found that I had to place the ``CorsWebFilter``` at the root of my application like so:
#SpringBootApplication
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
CurrencyWebClient client = new CurrencyWebClient();
System.out.println(client.getResult());
}
#Bean
CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
This of course, is not the only way to do it. But it solved this little initial problem I had. Thanks all.

Related

Spring Security / Keycloak: Securing the same request path with multiple realms

I'd like users in two different realms (eg human users and S2S users) to access the same rest endpoint. All of multi-tenancy examples I can find (eg keycloak multi-tenancy docs) suggest implementing a KeycloakConfigResolver to pick a single realm based on the request path. Eg:
public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
private final KeycloakDeployment realm1Deployment;
private final KeycloakDeployment realm2Deployment;
public PathBasedKeycloakConfigResolver() throws IOException {
realm1Deployment = buildDeployment("realm1.json");
realm2Deployment = buildDeployment("realm2.json");
}
#Override
public KeycloakDeployment resolve(HttpFacade.Request request) {
String path = request.getRelativePath();
return path.startsWith("clients/") ? realm1Deployment : realm2Deployment;
}
private static KeycloakDeployment buildDeployment(String path) throws IOException {
return KeycloakDeploymentBuilder.build(new ClasspathResource(path).getInputStream());
}
}
But this requires me to pick a single realm per request path.
I want different functionality, I'd like to try authenticating the request against multiple realms and pick the first the succeeds. I feel this would be the logical way to support multiple realms for a single URI but I'm open to suggestions for achieving this.
Since Keycloak provides OAuth2 functionality, you do not necessarily need to use the keycloak adapters (a lot of them are being deprecated because of this, even, see here). Instead you can just rely on the built in functionality of Spring Security.
An example of how to configure JWT Authentication for Spring Security with multiple issuers looks like this:
JwtIssuerAuthenticationManagerResolver authenticationManagerResolver = new JwtIssuerAuthenticationManagerResolver
("https://idp.example.org/issuerOne", "https://idp.example.org/issuerTwo");
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.authenticationManagerResolver(authenticationManagerResolver)
);
The separate issuer URLs in your case would be the issuer URLs of your respective realms. This example is taken directly from the Spring Security documentation, it also contains samples on how to achieve the same with XML configuration, should you prefer to use that.
Of course, migrating away from the adapter, if you're already using it might not be easy, but since the adapter is going away in the long term anyways, it might be worth evaluating doing so as early as possible
The Keycloak adapters deprecation is announced there.
You should have a look at this OpenID adapter I wrote. It works out of the box with as many issuers as you need and solves quite a few of keycloak spring-boot adapter limitations:
compatible with webmvc (servlets) and webflux (reactive) apps
spring boot 3 ready (does not extend WebSecurityConfigurerAdapter)
no adherence to Keycloak (works with any OpenID authorization-server)
tooling for security unit testing
Basic tutorial here.

Micrometer Prometheus metrics in jersey application (Non spring)

I have a web application (war) with Jersey REST endpoints. I am integrating with prometheus / micrometer for generating metrics. I have exposed "/metrics" endpoint as in here
#Path("/metrics")
public class Metrics {
private static final PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
static {
new JvmGcMetrics().bindTo(prometheusRegistry);
new JvmMemoryMetrics().bindTo(prometheusRegistry);
new JvmCompilationMetrics().bindTo(prometheusRegistry);
new JvmThreadMetrics().bindTo(prometheusRegistry);
}
#GET
public String getMetrics() {
return prometheusRegistry.scrape();
}
}
I am stuck on how to generate http request metrics. I could not find any code that would relevant to get these metrics. Can someone help me on this ?
Alternatively to what checketts proposed, you could make use of the Jersey server instrumentation of Micrometer which is present even prior to the 1.0.0 release in the form of micrometer-jersey2 library. You can find the source here.
Your entrypoint to this is the MetricsApplicationEventListener which can be registered with Jerseys ResourceConfig. For an example, you can have a look at the test class on how this could be done.
You can also have a look at how this is integrated/autoconfigured in Spring Boot here.
One last note: Spring Boots metric name is http.server.requests (to distinguish them from HTTP client request metrics) and if you one day will move to Spring Boot or your platform is already running Spring Boot applications, your non Spring Boot HTTP requests metrics will nicely match without further ado.
You'll need to include a Filter to record each request as it comes through. See https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilter.java for how Spring does it.
I would recommend against using a static registry if possible and using dependency injection instead.
Here is a tiny example of what you might do within a filter's doFilter method
long start = System.nanoTime()
try {
filterChain.doFilter(request, response);
long durationNanos = System.nanoTime() - start;
prometheusRegistry.timer("http.server.requests", "status", response.getStatus().toString()).record(durationNanos, TimeUnit.NANOSECONDS)
} catch (Exception ex) {
//Equivalent exception timer recording
throw ex;
}

How to set ViewResolver in Spring WebFlux

I've my Spring Boot Web Flux application for quite some time. At this point I wanted to add some exception handlers to my router function:
#Bean
RouterFunction<?> router(final GeneratorHandler generatorHandler) {
return resources("/**", new ClassPathResource("/static/"))
.andOther(route(GET("/generate"), generatorHandler::renderData)
.andRoute(GET("/index"), generatorHandler::renderIndex));
}
So I added another bean like this:
#Bean
HttpHandler httpHandler(final GeneratorHandler generatorHandler) throws Exception {
return WebHttpHandlerBuilder.webHandler(toHttpHandler(router(generatorHandler)))
.prependExceptionHandler((serverWebExchange, exception) -> {
//process here
return null;
})
.build();
}
After this I am having troubles with my view resolver. It can't find any of my views. After investigating I've realized that debugger does not stop in ThymeleafReactiveViewResolver class.
Is that possible that this change changed default view resolver too? How Can I bring it back?
Providing your httpHandler disables quite a lot of support from Spring Boot.
You can declare your own WebExceptionHandler, as a component (even an ordered one) and Spring WebFlux will pick it up for you. Without a more concrete example (or at least the stacktrace/error you're seeing), it's hard to understand what's going on.
Spring Boot now supports error handling in WebFlux applications (see #8625), in case it does what you're trying to achieve.

Spring Boot Application - what is default timeout for any rest API endpoint or a easy config to control all endpoint timeout

I am using current Spring boot version (1.4.x) and wondering if it has any default timeout for api calls. I have tested it by putting breakpoints but it was keep waiting and didn't time-out.
I was also trying to configure default timeout for all my spring-boot apps by using some annotation or yml settings.
I found couple of alternatives (one of them here) but using callable actually adding extra non-business logic code where setting something in xml bean is out of fashion in latest spring boot applications.
You can try server.connection-timeout=5000 in your application.properties.From the official documentation:
server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
UPDATE:
Just noticed that you use microservice architecture, so in case you need to handle timeouts when communicating between microservices, I would suggest handling it on the client side instead of the server side. If the microservice you are trying to call is overloaded and its performance degrades to the point where it drastically affects the user experience sometimes it's better to return some fallback data than just drop the request.
Imagine we have an e-commerce web-site that has microservice architecture and one of its microservices that gives recommendations to the user becomes extremely slow. In this case, the preferred solution would be to return some fallback data which could be top 10 popular products this month rather than showing 5xx error page to the customer. Moreover, in case subsequent requests fail with a timeout, we can make a decision to avoid sending requests to the 'recommendation-service' and return fallback data immediately. After some time we can try sending a request to the 'recommendation-service' again, and if it became healthy - just use it instead of the fallback data.
This is called Circuit Breaker pattern and there is already an implementation of it in a framework called Hystrix. Here is a nice article explaining it in depth: http://www.baeldung.com/spring-cloud-netflix-hystrix. Spring Cloud Feign + Spring Cloud Hystrix looks really nice especially taking into account that they work with Discovery services out-of-the-box (e.g. Spring Cloud Eureka).
I agree all above options and tried below option in my spring boot application. It works perfectly fine now. Below is the code sample as a bean. Now just need to #Autowire RestTemplate wherever(java class) I need it.
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(15000);
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setReadTimeout(15000);
return restTemplate;
}
There are a couple of ways to do this:
1) Using ClientHttpRequestFactory with RestTemplate:
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(timeinMillis);
factory.setConnectTimeout(timeinMillis);
return factory;
}
2) Second way is to use callable but I guess you have already explored that solution.
The timeout can be set using the connectionTimeout property of Tomcat.
Please refer this answer how to set it for Tomcat.
Configuring maxKeepAliveRequests in Spring Boot embedded Tomcat
You can create a configuration file using annotation #Configuration
For using RestTemplate:
` #Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofMillis(30000))
.setReadTimeout(Duration.ofMillis(30000))
.build();
}`
For WebClient Timeouts:
#Bean
public WebClient webClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create().responseTimeout(Duration.ofMillis(30000))
))
.build();
}
After the configuration is done, in a controller or any other file where you want to use this RestTemplate or WebClient just autowire it like:
#Autowired
private RestTemplate restTemplate;
or
#Autowired
private WebClient webClient;

A real-world controller example with Spring 5: Web Reactive

I want to be involved in a reactive programming world with Spring. As I realised, it gives me a choice between two different paradigms: the annotation-based (with well-known to us #Controller, #RequestMapping) and the reactive one (which is intended to resolve an "Annotation Hell").
My problem is a lack of understanding how a typical reactive controller will look like. There are three conceptual interfaces, which I can use in my controller class:
HandlerFunction<T> (1) - I define a method for each specific ServerRequest
which returns a concrete HandlerFunction<T> instance, then register these methods with a router. Right?
RouterFunction (2) and FilterFunction (3) - Is there a specific place where all RequestPredicates with corresponding HandlerFunctions should be placed? Or can I do it separately in each controller (as I used to do with the annotation approach)? If so, how then to notify a global handler (router, if any?) to apply this router part from this controller?
It's how I see a reactive controller "template" by now:
public class Controller {
// handlers
private HandlerFunction<ServerResponse> handleA() {
return request -> ok().body(fromObject("a"));
}
// router
public RouterFunction<?> getRouter() {
return route(GET("/a"), handleA()).and(
route(GET("/b"), handleB()));
}
// filter
public RouterFunction<?> getFilter() {
return route(GET("/c"), handleC()).filter((request, next) -> next.handle(request));
}
}
And, finally, how to say that it is a controller, without marking it with the annotation?
I've read the Spring reference and all posts related to this issue on the official blog. There is a plenty of samples, but all of them are pulled out of context (IMHO) and I can't assemble them into a full picture.
I would appreciate if you could provide a real-world example and good practices of how to organise interactions between these functions.
This is not a real world example, but so far Is how I view some kind of organization on this:
https://github.com/LearningByExample/reactive-ms-example
As far as I concerned:
RouterFunction is the closest analogue to #Controller (#RequestMapping precisely) in terms of new Spring approach:
Incoming requests are routed to handler functions with a
RouterFunction (i.e. Function>). A router function evaluates to a
handler function if it matches; otherwise it returns an empty result.
The RouterFunction has a similar purpose as a #RequestMapping
annotation. However, there is an important distinction: with the
annotation your route is limited to what can be expressed through the
annotation values, and the processing of those is not trivial to
override; with router functions the processing code is right in front
of you: you can override or replace it quite easily.
Then instead of Spring Boot SpringApplication.run in main method your run server manually by :
// route is your route function
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat server = new Tomcat();
Context rootContext = server.addContext("",
System.getProperty("java.io.tmpdir"));
Tomcat.addServlet(rootContext, "servlet", servlet);
rootContext.addServletMapping("/", "servlet");
tomcatServer.start();
There are both reactive and non-reactive approach. It's illustrated on Spring github

Categories

Resources