CORS error for 192.168.0.3/v1 but not for 192.168.0.3/v1/signup - spring

I am using Spring-boot config for basic-auth and when I am trying to access the http://192.168.0.3/v1 using credentials, I am getting CORS error, even though I have configurations for CORS.
The weird thing is, when I am accessing the http://192.168.0.3/v1/signup, I am able to create a user.
why CORS error for the root url access only?
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#ComponentScan(basePackages = { "com.ofloy.rest.security" })
#Import({CorsConfig.class})
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/signup/**").permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().csrf().disable()
;
}
}
#Configuration
public class CorsConfig {
#Bean
public FilterRegistrationBean<Filter> customCorsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<Filter>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
I am using UserDetailsService for querying the real user from my DB and set server.servlet.context-path = /v1/
Basically two issues I am facing with the above configuration:
I am able to access http://192.168.0.3/v1/signup but not
http://192.168.0.3/v1/ from the broweser, as getting CORS error.
Accessing http://192.168.0.3/v1(from POSTMAN) using the credentials to check if
the credentials are correct, give me the 404 error. 404 if
credentials are correct and 401 is not correct. Why 404?
Note: One thing I have noticed for second issues is, even if I send the POST request to http://192.168.0.3/v1, the spring Logs shows it GET request, here is the log stack.
DEBUG DispatcherServlet : GET "/v1/", parameters={}
WARN PageNotFound : No mapping for GET /v1/
DEBUG DispatcherServlet : Completed 404 NOT_FOUND
DEBUG DispatcherServlet : "ERROR" dispatch for GET "/v1/error", parameters={}
DEBUG RequestMappingHandlerMapping : Mapped to public
org.springframework.http.ResponseEntity org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
DEBUG HttpEntityMethodProcessor : Using 'application/json', given
[/] and supported [application/json, application/*+json]
DEBUG HttpEntityMethodProcessor : Writing [{timestamp=Wed Jan 30 16:16:40 IST 2019, status=404, error=Not Found, message=No message available,
path=/v1/}]
DEBUG DispatcherServlet : Exiting from "ERROR" dispatch, status 404
UPDATE: this is the CORS error in browser
Access to XMLHttpRequest at 'http://192.168.43.70:8085/v1' from
origin 'http://localhost:3007' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
Redirect is not allowed for a preflight request.

I would do something like below on the controller which handles the request:
#CrossOrigin(origins = "http://localhost:3007")
#RestController
#RequestMapping("/v1")
public class VoneController {

Related

CORS preflight did not succeed with Spring Boot and Kotlin [duplicate]

I use Spring Boot with Spring Security and Cors Support.
If I execute following code
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send
I get as a result
200
If I test with wrong credentials like
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send
instead of getting 401 (that is the standard code for wrong authentication in spring security) I get
0
with following browser notification:
GET http://localhost:5000/api/token
XMLHttpRequest cannot load http://localhost:5000. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
I'm developing front-end code that needs useful http status codes from server responses to handle the situation. I need something more useful than 0. Also the response body is empty. I dont know if my config is wrong, or it's a software bug and I also don't know where, if it's chromium (using arch linux) or spring security.
My Spring Config is:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
#RestController
#RequestMapping("api")
public class Controller {
#RequestMapping("token")
#CrossOrigin
Map<String, String> token(HttpSession session) {
return Collections.singletonMap("token", session.getId());
}
}
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
If I test with curl everything works perfect, I think because no CORS support needed, but I tried to simulate the CORS with OPTION requests and the result was also ok.
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested- With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
<
* Connection #0 to host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}
and with wrong credentials:
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
<
* Connection #0 to host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}
Edit:
To avoid misunderstandings. I use 1.3.3 Spring Boot.
The Blog post writes:
CORS support will be available in the upcoming Spring Boot 1.3 release, and is already available in the 1.3.0.BUILD-SNAPSHOT builds.
Using controller method CORS configuration with #CrossOrigin annotations in your Spring Boot application does not require any specific configuration.
Global CORS configuration can be defined by registering a WebMvcConfigurer bean with a customized addCorsMappings(CorsRegistry) method:
I have added following code to enable global cors support. actually I have tried this before but it the result was the same. I tried it again recently and the result is the same.
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
The idea, that the problem comes from a redirect between the authorization process is an interesting though. how can i change the redirect to any resources to avoid this conflict?
EDIT:
I guess I am closer to a solution. I have tested with my nodejs server that supports cors without problems by adding
Access-Control-Allow-Origin: *
to all requests.
Like Stefan Isele has already mentioned it seems that spring security redirects or doesn't add the CORS header so that's why the request seems to be broken. So while spring security is checking the authentification it has to add the proper header.
Does anyone know how to do so?
EDIT:
I found a workaround, that seems to be ugly. I have started a github issue for spring boot where I describe the workaround: https://github.com/spring-projects/spring-boot/issues/5834
Spring Security can now leverage Spring MVC CORS support described in this blog post I wrote.
To make it work, you need to explicitly enable CORS support at Spring Security level as following, otherwise CORS enabled requests may be blocked by Spring Security before reaching Spring MVC.
If you are using controller level #CrossOrigin annotations, you just have to enable Spring Security CORS support and it will leverage Spring MVC configuration:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
If you prefer using CORS global configuration, you can declare a CorsConfigurationSource bean as following:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
This approach supersedes the filter-based approach previously recommended.
You can find more details in the dedicated CORS section of Spring Security documentation.
If you use JDK 8+, there is a one line lambda solution:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
How to Solve CORS on Spring Boot 2.3+
Summary
If you are facing this CORS issue, don't worry. It's a common issue for every backend developer when they try to integrate with front-end microservices for the first-time. It's some sort of security policy that browsers are strictly applying for the safety of the users and that's why you are not facing it when you tried your API via Postman/Swagger or cURL.
Solutions
Client-Side Bypass (Dev Only)
Following solutions are just only for development purposes, you absolutely need to solve this CORS issue permanently for your production environment. You can use the following browser extensions to bypass browser policies for CORS error but don't get surprised if they didn't work properly.
CORS Unblock Firefox - Chrome
CORS Everywhere Firefox
Production Solutions
There are different ways to configure CORS policies on the application and it's completely based on your deployment architecture. For example, if your application is going to be exposed through Reverse Proxies (like Nginx), API Gateways (Kong), Service Mesh Sidecar Proxies (i.e Envoy), Kubernetes NGINX Ingress, and so forth, the Best Practice is to handle the CORS configuration on the Edge layer because sometimes they don't consider lower layers headers and they overwrite them and you will still receive CORS errors from the Browser.
I have listed useful links for the configuration of edge layers in the following
Kubernetes NGINX Ingress Controller CORS - Stackoverflow / Official User Manual
Kong API Gateway - KongHQ
Nginx - Geekflare
Apache - Geekflare
HA Proxy - Official Website
Istio - Discuss.Istio
But, If you are going to deploy and expose your APIs through SprintBoot's built-in web server, you can use the instructions in the next.
Instructions to Enable CORS Globally - Spring Boot Application
If you don't have any implementation for WebSecurityConfig, Just easily do the following steps:
Add the following dependency [spring-boot-starter-security]
to your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Create a new class in your config package that extends
WebSecurityConfig (i.e 'SecurityConfig')
Put the following codes into the created file:
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.cors.CorsConfiguration;
import java.util.List;
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("*"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
// You can customize the following part based on your project, it's only a sample
http.authorizeRequests().antMatchers("/**").permitAll().anyRequest()
.authenticated().and().csrf().disable().cors().configurationSource(request -> corsConfiguration);
}
}
Now you need to customize the CORS configuration based on your need:
setAllowedHeaders-> you have to specify which parameters are allowed to be sent to the backend services through the front-end app, for example, if you are using Bearer/Basic Token Authorization methods, you need to pass your JWT-Token through the "Authorization" header. So you need to make sure that backed would accept this data accordingly and for this purpose, you must put "Authorization" in the list of Allowed-Headers.
setAllowedMethods-> Do not forget to put "OPTIONS" method in the list for Pre-flight process. Don't worry, read more here!
setAllowCredentials-> If you are using Authorization header, set it True.
setExposedHeaders-> If you are returning data through Response Headers, you need to specify them here. for example, some APIs are designed to return Authorization token after success /authentication through Response Headers. Thus, the related header needs to be exposed accordingly.
setAllowedOrigins-> You must specify the domains that are eligible to send requests to your backend applications. for example, if your application is hosted on https://penguin.com and your APIs are on https://api.penguin.com, you need to allow "https://penguing.com" to send requests to your backend. Also, you are able to pass wildcard (*) to allow any domains to send requests to your backend. But it's recommended to not use "any" unless you are providing public APIs or you are deploying in the non-production environments.
There is an important misunderstanding for the people that may think CORS can avoid misuses of the APIs by/on other platforms (i.e phishing purposes). It's not true, CORS Policies are browser-based policies and can be bypassed easily through proxies, so it only makes the misuse process a little bit harder, but it does not make immunity.
Build/Run your application, Test your APIs, and rest ( Everyone knows CORS headache )
Alternative Solutions
You can use the following links:
Spring.io | Enabling Cross-Origin Requests for a RESTful Web Service
Bealdung | CORS with Spring
If you are using Spring Security, you can do the following to ensure that CORS requests are handled first:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors().and()
...
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
See Spring 4.2.x CORS for more information.
Without Spring Security this will work:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS");
}
};
}
Cross origin protection is a feature of the browser. Curl does not care for CORS, as you presumed.
That explains why your curls are successful, while the browser requests are not.
If you send the browser request with the wrong credentials, spring will try to forward the client to a login page.
This response (off the login page) does not contain the header 'Access-Control-Allow-Origin' and the browser reacts as you describe.
You must make spring to include the haeder for this login response, and may be for other response, like error pages etc.
This can be done like this :
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
This is copied from cors-support-in-spring-framework
I would start by adding cors mapping for all resources with :
registry.addMapping("/**")
and also allowing all methods headers..
Once it works you may start to reduce that again to the needed minimum.
Please note, that the CORS configuration changes with Release 4.2.
If this does not solve your issues, post the response you get from the failed ajax request.
// CorsConfig.java file
#Configuration
public class CorsConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowCredentials(true);
}
}
As of 2021, this is maybe the simplest solution, just need to create a separate class.
That's all.
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("*");
}
};
}
Found an easy solution for Spring-Boot, Spring-Security and Java-based config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
I had the same problem on a methood that returns the status of the server.
The application is deployed on multiple servers. So the easiest I found is to add
#CrossOrigin(origins = "*")
#RequestMapping(value="/schedulerActive")
public String isSchedulerActive(){
//code goes here
}
This method is not secure but you can add allowCredentials for that.
I solved this problem by:
`
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers","Access-Control-Allow-Origin","Access-Control-Request-Method", "Access-Control-Request-Headers","Origin","Cache-Control", "Content-Type", "Authorization"));
configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
`
I solved this problem by:
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
#Configuration
public class CORSFilter extends CorsFilter {
public CORSFilter(CorsConfigurationSource source) {
super((CorsConfigurationSource) source);
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Headers",
"Access-Control-Allow-Origin, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
if (response.getHeader("Access-Control-Allow-Origin") == null)
response.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, response);
}
}
and:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
#Configuration
public class RestConfig {
#Bean
public CORSFilter corsFilter() {
CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedMethod(HttpMethod.DELETE);
config.addAllowedMethod(HttpMethod.GET);
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.PUT);
config.addAllowedMethod(HttpMethod.POST);
((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", config);
return new CORSFilter(source);
}
}
Cors can be a pain in the ass, but with this simple code you are Cors ONLY!!!! to to specified method
#CrossOrigin(origins="*")// in this line add your url and thats is all for spring boot side
#GetMapping("/some")
public String index() {
return "pawned cors!!!!";
}
Like a charm in spring boot 2.0.2
I was having major problems with Axios, Spring Boot and Spring Security with authentication.
Please note the version of Spring Boot and the Spring Security you are using matters.
Spring Boot: 1.5.10
Spring: 4.3.14
Spring Security 4.2.4
To resolve this issue using Annotation Based Java Configuration I created the following class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("youruser").password("yourpassword")
.authorities("ROLE_USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().
authorizeRequests()
.requestMatchers(CorsUtils:: isPreFlightRequest).permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.realmName("Biometrix");
http.csrf().disable();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization"));
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
One of the major gotchas with Axios is that when your API requires authentication it sends an Authorization header with the OPTIONS request. If you do not include Authorization in the allowed headers configuration setting our OPTIONS request (aka PreFlight request) will fail and Axios will report an error.
As you can see with a couple of simple and properly placed settings CORS configuration with SpringBoot is pretty easy.
You can finish this with only a Single Class, Just add this on your class path.
This one is enough for Spring Boot, Spring Security, nothing else.
:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsFilterConfig implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype");
response.setHeader("Access-Control-Max-Age", "3600");
if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
After much searching for the error coming from javascript CORS, the only elegant solution I found for this case was configuring the cors of Spring's own class org.springframework.web.cors.CorsConfiguration.CorsConfiguration()
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
// https://docs.spring.io/spring-boot/docs/2.4.2/reference/htmlsingle/#boot-features-cors
#Configuration
public class MyConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*").allowedHeaders("*");
}
};
}
}
If using Spring Security, set additional:
// https://docs.spring.io/spring-security/site/docs/5.4.2/reference/html5/#cors
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
// ...
// if Spring MVC is on classpath and no CorsConfigurationSource is provided,
// Spring Security will use CORS configuration provided to Spring MVC
http.cors(Customizer.withDefaults());
}
}
For properties configuration
# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.
Kotlin solution
...
http.cors().configurationSource {
CorsConfiguration().applyPermitDefaultValues()
}
...
Solution for Webflux (Reactive) Spring Boot, since Google shows this as one of the top results when searching with 'Reactive' for this same problem. Using Spring boot version 2.2.2
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.cors().and().build();
}
#Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues();
config.addAllowedHeader("Authorization");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
For a full example, with the setup that works with a custom authentication manager (in my case JWT authentication). See here https://gist.github.com/FiredLight/d973968cbd837048987ab2385ba6b38f
Note that new CorsConfiguration().applyPermitDefaultValues() only allows GET, POST and HEAD methods. If you are looking for PUT or DELETE, you have to set the methods manually (like below). Finally, don't forget the OPTIONS method which is required to preflight PUT, PATCH and DELETE methods (CORS error will still occur otherwise).
import static org.springframework.web.cors.CorsConfiguration.ALL;
#Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedMethods(Arrays.asList(
HttpMethod.GET.name(),
HttpMethod.POST.name(),
HttpMethod.DELETE.name(),
HttpMethod.PUT.name(),
HttpMethod.HEAD.name(),
HttpMethod.POST.name(),
HttpMethod.OPTIONS.name()
));
config.setAllowedHeaders(Collections.singletonList(ALL));
config.setAllowedOrigins(Collections.singletonList(ALL));
config.setMaxAge(1800L);
source.registerCorsConfiguration("/**", config);
return source;
}
In class implement WebMvcConfigurer you have to Override method addCorsMappings
public class WebMvcConfig implements WebMvcConfigurer {
private final long MAX_AGE_SECS;
#Value("${appConfig.cors.allowedOrigins}")
private String[] allowedOrigins;
public WebMvcConfig() {
MAX_AGE_SECS = 3600;
}
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(allowedOrigins)
.allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(MAX_AGE_SECS);
}
}
You need to look at especially this method : configure( HttpSecurity httpSecurity )
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*")
.allowedMethods("HEAD", "GET", "PUT", "POST",
"DELETE", "PATCH").allowedHeaders("*");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/images/**").permitAll()
.antMatchers(HttpMethod.POST,"/api/login").permitAll()
.antMatchers(HttpMethod.POST,"/api/user").permitAll()
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); // Add our custom JWT security filter
UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(request -> {
var cors = new CorsConfiguration();
cors.setAllowedOrigins(List.of("http://localhost:4200", "http://127.0.0.1:80", "http://example.com"));
cors.setAllowedMethods(List.of("GET","POST", "PUT", "DELETE", "OPTIONS"));
cors.setAllowedHeaders(List.of("*"));
return cors;
}).and()...
}
}

hasAuthoritiy() work on one place but not on another....Spring Security problem

#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/worker/login/").permitAll()
.and().authorizeRequests().antMatchers("/item/").hasAuthority("USER")
.and().authorizeRequests().antMatchers("/worker/getUserDetails/").hasAuthority("USER")
.anyRequest().authenticated().and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors();
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
It works for path "/worker/getUserDetails/", it works only if user is logged. But after logging path "/item/ is always 403(forbidden). Here is my controller for getUserDetails:
#GetMapping("/getUserDetails")
public ResponseEntity<Worker> getUsername(#RequestHeader(value="Authorization") String jwtHeader){
String username=jwtUtil.extractUsername(jwtHeader.substring(7));
return ResponseEntity.ok(workerService.findByUsername(username));
}
And also controller for /item/ path:
#GetMapping("/")
public ResponseEntity<List<Item>> getAllItems(){
return new ResponseEntity<>(itemService.noSale(), HttpStatus.OK);
}
And MyUserDetials where i set actual role:
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority(worker.getRole()));
}
Edit: Here is what security logs say2021-10-19 13:26:17.450 DEBUG 7288 --- [nio-8080-exec-5] o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /item/noSale/] with attributes [hasAuthority('USER')] 2021-10-19 13:26:17.451 DEBUG 7288 --- [nio-8080-exec-5] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access 2021-10-19 13:26:17.453 DEBUG 7288 --- [nio-8080-exec-5] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request 2021-10-19 13:26:17.460 DEBUG 7288 --- [nio-8080-exec-5] o.s.security.web.FilterChainProxy : Securing GET /error
On postman it is working, only on react side it doesn't work, so problem is with cors probably
#Bean
public CorsFilter corsFilter() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return new CorsFilter(source);
}

Failed to authenticate with NimbusJwtDecoder withJwkSetUri

I am trying to setup Resource Server to validate jwt tokens with Authentication server by using NimbusJwtDecoder.withJwkSetUri
Following is my configuration in Resource server
#Configuration
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.oauth2ResourceServer(c -> {
c.jwt(j -> {
j.decoder(jwtDecoder());
});
});
http.authorizeRequests().anyRequest().authenticated();
}
#Bean
public JwtDecoder jwtDecoder(){
RestTemplate rest = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors = rest.getInterceptors();
interceptors.add(new BasicAuthenticationInterceptor("client1","secret1"));
interceptors.add(new LoggingInterceptor());
rest.setInterceptors(interceptors);
return NimbusJwtDecoder.withJwkSetUri("http://localhost:8080/oauth/token_key").restOperations(rest).build();
}
}
And I have simple endpoint in Resource server to test
#RestController
public class HelloController {
#GetMapping("/hello")
public String hello(){
return "Hello";
}
}
However when I access "/hello" with access token already got from auth server then I get unauthorised response and observe following logs in Resource server.
Response body: {"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo8ieQxTVHq4jBSM3JpO7UcFOa5UrorX5KhRbMqEtT746yGTqqv+t1EW6l8G31bGc6G/IHy7032vpKNxAgLVcoCrdoOakbGLb1y2+ElB9QmEEEplARWLQ43t47ywd0UA7MhF9WIbud1Z6kqySrsrBTzjPu+fwCElzUFveyaiPsZDlrEAU6yMLQ23nEP3bBCgDtGMVs1a7RsmAzfUsruelqNaAQQamobkjEMWB8ewZWjtsriIldNjGEAUznw4bcJ963ExtmgfMAHS7XhuWqu58yIzdBopxhZvt/falc5cyp7OCP1ZPEjkHJ5TikJksqOgDgWhiIVtr/3cUjd8vnX4y4QIDAQAB\n-----END PUBLIC KEY-----"}
2021-05-15 11:54:47.468 DEBUG 40223 --- [nio-9090-exec-3] o.s.web.client.RestTemplate : Response 200 OK
2021-05-15 11:54:47.468 DEBUG 40223 --- [nio-9090-exec-3] o.s.s.o.s.r.a.JwtAuthenticationProvider : Failed to authenticate since the JWT was invalid
2021-05-15 11:54:47.469 DEBUG 40223 --- [nio-9090-exec-3] w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
2021-05-15 11:54:47.469 DEBUG 40223 --- [nio-9090-exec-3] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
It seems auth server was able to provide public key successfully but resource server could not use this public key to validate provided jwt token.
Any help is highly appreciated.
Hi please add class #EnableAuthorizationServer anotation but not working please read this Outh2 documentation https://projects.spring.io/spring-security-oauth/docs/oauth2.html

Pre-flight request is authenticated even if CorsFilter is enabled in Spring Boot

I am using Spring Security for OAuth authentication and I have configured the Cors. However, my all preflight request fails dues to authentication since the preflight request does not have a token(That is how it should be). I have the following configuration class;
SecurityConfiguration.java
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(final HttpSecurity security) throws Exception {
security.cors()
.and()
.requestMatchers()
.antMatchers("/actuator/health")
.and()
.authorizeRequests()
.antMatchers("/actuator/health").permitAll()
.and()
.csrf().disable();
// Custom filter to validate if user is authorized and active to access the system
security.addFilterAfter(new AuthorizationFilter(), BasicAuthenticationFilter.class);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration().applyPermitDefaultValues();
configuration.setAllowedMethods(Arrays.asList("GET","HEAD","POST","PUT"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
WebMvcConfiguration .java
#Configuration
public; class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET","HEAD","POST","PUT");
}
}
Questions:
Why preflight request goes to authentication even if I have CorsFilter enable?
How can I exclude preflight request to be authenticated ?
UPDATE:
I enabled log for debugging the issue using logging.level.org.springframework.security.web.FilterChainProxy: DEBUG in application.yml file.
I fetched the list of filter registered in filter chain and list is as follow :
class org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter
class org.springframework.security.web.context.SecurityContextPersistenceFilter
class org.springframework.security.web.header.HeaderWriterFilter
class org.springframework.web.filter.CorsFilter
class org.springframework.security.web.authentication.logout.LogoutFilter
class org.springframework.security.web.savedrequest.RequestCacheAwareFilter
class org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
class org.springframework.security.web.authentication.AnonymousAuthenticationFilter
class org.springframework.security.web.session.SessionManagementFilter
class org.springframework.security.web.access.ExceptionTranslationFilter
class org.springframework.security.web.access.intercept.FilterSecurityInterceptor
class org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter
Notice that corsFilter is registered. However, when I get request only following filters are running and not CorsFilter;
'WebAsyncManagerIntegrationFilter'
'SecurityContextPersistenceFilter'
'HeaderWriterFilter'
'LogoutFilter'
'BearerTokenAuthenticationFilter'
'RequestCacheAwareFilter'
'SecurityContextHolderAwareRequestFilter'
'AnonymousAuthenticationFilter'
'SessionManagementFilter'
'ExceptionTranslationFilter'
'FilterSecurityInterceptor'
UPDATE 2:
While testing, I noticed for '/actuator/health', CorsFilter is being called. But I am not sure what does that mean?
Adding the following to your configuration security.cors() should have enabled the CORS filter which should enable the pre-flight request to work without an authorization token.But it seems you have configured your requests machers incorrectly, please use correct url mappings so that the security configuration will apply to all endpoints.
Also,Try setting your allowed origins as well to cover all origins:
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration().applyPermitDefaultValues();
configuration.setAllowedMethods(Arrays.asList("GET","HEAD","POST","PUT"));
configuration.setAllowedOrigins(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Guide : https://www.baeldung.com/spring-security-multiple-entry-points

Problem calling a "bearer-only" keycloak endpoint from a springboot (client app) to a also spring boot (bearer only app)

Basically I'm trying to access a bearer-only endpoint from a client app which is using a "KeycloakRestTemplate".
I did follow this guidelines 1:1 (it is in German) : https://blog.codecentric.de/2017/09/keycloak-und-spring-security-teil-1-einrichtung-frontend/
My problem is that when I see the logs, the authentication on the side of the bearer only endpoint seems successful, as shown bellow:
Found [1] values in authorization header, selecting the first value for Bearer.
o.k.a.BearerTokenRequestAuthenticator : Verifying access_token
o.k.a.BearerTokenRequestAuthenticator : access_token: [LONG TOKEN HERE]
o.k.a.RefreshableKeycloakSecurityContext : checking whether to refresh.
org.keycloak.adapters.AdapterUtils : use realm role mappings
org.keycloak.adapters.AdapterUtils : Setting roles:
org.keycloak.adapters.AdapterUtils : role: create_vouchers
org.keycloak.adapters.AdapterUtils : role: public_realm_access
org.keycloak.adapters.AdapterUtils : role: overview_orders
org.keycloak.adapters.AdapterUtils : role: uma_authorization
User 'c1500da2-855f-4306-ab65-662160558101' invoking 'http://localhost:8082/articles' on client 'articlesBearerOnlyService'
o.k.adapters.RequestAuthenticator : Bearer AUTHENTICATED
.k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /articles
o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8082/articles
cors validation not needed as were not a secure session or origin header was null: {0}
o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
but then directly afterwards on the logs comes this:
o.k.adapters.PreAuthActionsHandler : adminRequest http://localhost:8082/login
o.k.adapters.PreAuthActionsHandler : checkCorsPreflight http://localhost:8082/login
.k.a.t.AbstractAuthenticatedActionsValve : AuthenticatedActionsValve.invoke /login
o.k.a.AuthenticatedActionsHandler : AuthenticatedActionsValve.invoke http://localhost:8082/login
o.k.a.AuthenticatedActionsHandler : Origin: null uri: http://localhost:8082/login
o.k.a.AuthenticatedActionsHandler : cors validation not needed as were not a secure session or origin header was null: {0}
o.k.a.AuthenticatedActionsHandler : Policy enforcement is disabled.
so, it tries to redirect to adminRequest http://localhost:8082/login? why, and how could this be solved?
I did also also tried with postman (getting the acces-token from the token end-point) and pasting it on the Authorization header of this "bearer-only" endpoint, and similarly by seeing the logs, the user seems authorized exacltly like in the first log block above, the diference is that is doesn't try to redirect anywhere but I receive a 401.
{
"timestamp": "2019-09-05T11:18:51.347+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/articles" }
Could somebody please provide some guidance into a possible solution?
Thanks in advance!
----------------------------------------
EDITED
----------------------------------------
here is the application properties file:
server.port = 8082
spring.application.name = articleBearerOnlyService
keycloak.auth-server-url=http://localhost:8080/auth
keycloak.realm=[REALM]
keycloak.resource=articlesBearerOnlyService
keycloak.bearer-only=true
keycloak.cors=true
keycloak.credentials.secret=[SECRET]
keycloak.ssl-required = external
# access controlled through spring security
#keycloak.security-constraints[0].auth-roles[0]=overview_orders
#keycloak.security-constraints[0].security-collections[0].patterns[0]=/articles
logging.level.org.keycloak=TRACE
and here the SecurityConfig :
#KeycloakConfiguration
#EnableWebSecurity
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
private final KeycloakClientRequestFactory keycloakClientRequestFactory;
public SecurityConfig(KeycloakClientRequestFactory keycloakClientRequestFactory) {
this.keycloakClientRequestFactory = keycloakClientRequestFactory;
//to use principal and authentication together with #async
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
/* remove default spring "ROLE_" prefix appending to keycloak's roles*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
// NullAuthenticatedSessionStrategy() for bearer-only services
return new NullAuthenticatedSessionStrategy();
}
/* configure cors & requests handling behaviour*/
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.cors()
.and()
.csrf()
.disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(sessionAuthenticationStrategy())
.and()
.authorizeRequests()
.antMatchers("/articles").hasRole("overview_orders")
.anyRequest().permitAll();
}
// Spring boot integration
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
// *************************** Avoid Bean redefinition ********************************
#Bean
public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
KeycloakAuthenticationProcessingFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
#Bean
public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
KeycloakPreAuthActionsFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
#Bean
public FilterRegistrationBean keycloakAuthenticatedActionsFilterBean(
KeycloakAuthenticatedActionsFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
#Bean
public FilterRegistrationBean keycloakSecurityContextRequestFilterBean(
KeycloakSecurityContextRequestFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
#Bean
#Override
#ConditionalOnMissingBean(HttpSessionManager.class)
protected HttpSessionManager httpSessionManager() {
return new HttpSessionManager();
}
}
The #SpringBootApplication annotation is a composite of these three annotations: #EnableAutoConfiguration, #ComponentScan and #Configuration. Annotating a class e.g. com.example.demo.DemoApplication with #SpringBootApplication, results in Spring looking for other components, configurations, and services inside com.example.demo and all of its sub-packages.
A class like com.example.config.DemoConfig therefore cannot be found by Spring automatically. If you want, you can give hints to Spring where to look for components via #ComponentScan(basePackages = "com.some.package"). Check out this article if you like to know more.
In this particular case, my #KeycloakConfiguration class SecurityConfig{...}, was completely ignored, and thus the application behaved as if none security config was provided at all.
Now, why was the SecurityConfig ignored?
- it turned out to be (I almost feel shame) path location of the class; I usually would place such a class under:
com.[company].[domain].configuration
In my case (since I'm only prototyping with keycloak + spring and not particularly concerned with class location right now). I did place my SecurityConfig class under:
com.[company].configuration
This made spring boot completely ignore this class.
Follow up question: I'm new to Sprint boot, is it 100% necessary to place all code under "com.[company].[domain].configuration", without modifying the pom (just having a newly created vanilla springboot project via the initializr)?

Resources