The documentation clearly says:
By default, Spring Security requires that every request be authenticated.
I tried it and it's not the case.
I created a plain Spring Framework Java project (no Spring Boot) and defined the following bean:
@Bean
public SecurityFilterChain testFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.build();
}
All requests are not required to be authenticated. In fact there is not even a filter chain with a AuthorizationFilter
.
Same result when not defining a SecurityFilterChain
bean.
Am I missing something or is the documentation just wrong?
Edit: The project is setup correctly. The configuration class has the @EnableWebSecurity
annotation and as soon as I add .authorizeHttpRequests().anyRequest().authenticated()
to the configuration then every request has to be authenticated.
documentation is correct, you just took it out of context. The complete passage is:
By default, Spring Security requires that every request be authenticated. That said, any time you use an HttpSecurity instance, it’s necessary to declare your authorization rules.
every request is authenticated AS LONG AS you haven't provided your own SecurityFilterChain
bean. If you did, it now behaves the way YOU have set it up.
Since you insist that you experienced different behavior I specifically tested it.
I created a simple spring boot application:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.asgarov</groupId>
<artifactId>spring-security-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-demo</name>
<description>spring-security-demo</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
I then defined a single controller class
@RestController
public class HomeController {
@GetMapping
public String helloWorld() { return "Hello World"; }
}
and just like expected, upon trying to access localhost:8080
in browser I got redirected to the login page, here are the logs:
2024-07-17T20:41:00.287+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] o.s.security.web.FilterChainProxy : Securing GET /
2024-07-17T20:41:00.291+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2024-07-17T20:41:00.300+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:8080/?continue to session
2024-07-17T20:41:00.302+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using And [Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@1e687528, matchingMediaTypes=[application/xhtml+xml, image/*, text/html, text/plain], useEquals=false, ignoredMediaTypes=[*/*]]]
2024-07-17T20:41:00.302+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] s.w.a.DelegatingAuthenticationEntryPoint : Match found! Executing org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@f0020b1
2024-07-17T20:41:00.303+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-2] o.s.s.web.DefaultRedirectStrategy : Redirecting to http://localhost:8080/login
2024-07-17T20:41:00.314+02:00 DEBUG 1873324 --- [spring-security-demo] [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /login
After I defined the same config as yours:
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain testFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.build();
}
}
I could access the localhost:8080
also curl output curl -v localhost:8080
* Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 200
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 11
< Date: Wed, 17 Jul 2024 18:45:26 GMT
<
* Connection #0 to host localhost left intact
Hello World
So just like the documentation says SpringBoot will register defaultSecurityFilterChain ONLY when you haven't defined one. You can find the code for it in SpringBootWebSecurityConfiguration
class. There you will see the following configuration:
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
static class SecurityFilterChainConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests.anyRequest().authenticated());
http.formLogin(withDefaults());
http.httpBasic(withDefaults());
return http.build();
}
}
This configuration simply makes sure that every request is authenticated and registers default httpBasic athentication and formLogin (as explained here).
And since it is annotated with @ConditionalOnDefaultWebSecurity
it will only be activated when the user has not defined their own configuration