I am migrating from spring boot 2.7.18 to spring boot 3.2.x and I have noticed a strange behavior in spring security configuration on the basis of spring profile.
I am creating a spring cloud config server with basic authentication as follows.
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
My basic spring security looks like below
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
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.WebSecurityCustomizer;
import org.springframework.security.web.SecurityFilterChain;
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfiguration {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web ->
web.ignoring()
.requestMatchers(
"/meta/**",
"/encrypt/**");
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.httpBasic(Customizer.withDefaults())
.csrf(csrf -> csrf.ignoringRequestMatchers("/decrypt/**"))
.build();
}
}
application.yml file looks like below
spring:
application:
name: demo
cloud:
config:
server:
git:
uri: https://github.com/uri
username: name
password: password
basedir: /app/config/cache
defaultLabel: master
cloneOnStart: true
force-pull: true
server:
port: 8888
ssl.enabled: false
servlet.jsp.registered: false
eureka:
client:
enabled: false
---
spring:
config:
activate:
on-profile: secure
security:
user:
password: "secret"
cloud:
config:
server:
encrypt:
enabled: true
encrypt:
key: cipher text
Now when I run my config server, it starts with the profile default. Here authentication is done which is expected by default. But when I run the application with profile secure, all profile settings are loaded from application.yml file except
security:
user:
password: "secret"
ie let's say we call endpoint /decrypt without password secret, it should return 401. But we are getting 200. I am just confused why server.encrypt.enabled is loaded and not just spring.security.user.password?? Isn't only requests with password: secret should be allowed for profile: secure??
Spring boot 2.7.18 is working fine without any issues.
Comment From: Subrhamanya
I was able to debug. It tested 3 scenarios for the above configuration to the endpoint /decrypt:
- With
username: userandpassword: secretresult -->200 ok--> Expected - With
username: subbuandpassword: secretresult -->401 unauthorized--> Expected - With no authentication or any headers, simply hit
http://localhost:8888/decryptresult -->400 Bad request--> Unexpected
Logs says:
For scenarion 1:
2024-03-16T20:59:41.442+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [Mvc [pattern='/decrypt/**']]]]
2024-03-16T20:59:41.442+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (7/12)
2024-03-16T20:59:41.442+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2024-03-16T20:59:41.442+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.security.web.FilterChainProxy : Invoking BasicAuthenticationFilter (8/12)
2024-03-16T20:59:41.445+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.s.w.a.www.BasicAuthenticationFilter : Found username 'user' in Basic Authorization header
2024-03-16T20:59:41.445+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2024-03-16T20:59:41.445+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-03-16T20:59:41.445+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-03-16T20:59:41.445+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.s.authentication.ProviderManager : Authenticating request with DaoAuthenticationProvider (1/1)
2024-03-16T20:59:41.945+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-2] o.s.s.a.dao.DaoAuthenticationProvider : Authenticated user
2024-03-16T20:59:41.946+05:30 TRACE 1432 --- [demo] [nio-8888-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
For scenarion 2:
2024-03-16T21:01:37.806+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Securing POST /decrypt
2024-03-16T21:01:37.806+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking DisableEncodeUrlFilter (1/12)
2024-03-16T21:01:37.806+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (2/12)
2024-03-16T21:01:37.806+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderFilter (3/12)
2024-03-16T21:01:37.806+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (4/12)
2024-03-16T21:01:37.806+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking CorsFilter (5/12)
2024-03-16T21:01:37.807+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (6/12)
2024-03-16T21:01:37.807+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [Mvc [pattern='/decrypt/**']]]]
2024-03-16T21:01:37.807+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (7/12)
2024-03-16T21:01:37.807+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.security.web.FilterChainProxy : Invoking BasicAuthenticationFilter (8/12)
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.s.w.a.www.BasicAuthenticationFilter : Found username 'subbu' in Basic Authorization header
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] .s.s.w.c.SupplierDeferredSecurityContext : Created SecurityContextImpl [Null authentication]
2024-03-16T21:01:37.808+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.s.authentication.ProviderManager : Authenticating request with DaoAuthenticationProvider (1/1)
2024-03-16T21:01:38.039+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-4] o.s.s.a.dao.DaoAuthenticationProvider : Failed to find user 'subbu'
2024-03-16T21:01:38.047+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2024-03-16T21:01:38.047+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'refreshEventListener'
2024-03-16T21:01:38.047+05:30 TRACE 1432 --- [demo] [nio-8888-exec-4] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'liveReloadServerEventListener'
2024-03-16T21:01:38.047+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-4] o.s.s.w.a.www.BasicAuthenticationFilter : Failed to process authentication request
Here comes scenario 3:
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.b.w.s.f.OrderedRequestContextFilter : Bound request context to thread: org.apache.catalina.connector.RequestFacade@7d4fe239
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'encryptionController'
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/meta/**'], Filters=[]] (1/3)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=Mvc [pattern='/encrypt/**'], Filters=[]] (2/3)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@504862f6, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@45f73e21, org.springframework.security.web.context.SecurityContextHolderFilter@7b786ca7, org.springframework.security.web.header.HeaderWriterFilter@6bc7fad3, org.springframework.web.filter.CorsFilter@19c17e74, org.springframework.security.web.csrf.CsrfFilter@48c3b7d8, org.springframework.security.web.authentication.logout.LogoutFilter@3291d00f, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@43bf1376, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3ad6996b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@b57a91e, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4d00c8a5, org.springframework.security.web.access.ExceptionTranslationFilter@38040abe]] (3/3)
2024-03-16T21:03:56.667+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Securing POST /decrypt
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking DisableEncodeUrlFilter (1/12)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (2/12)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderFilter (3/12)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (4/12)
2024-03-16T21:03:56.667+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking CorsFilter (5/12)
2024-03-16T21:03:56.668+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (6/12)
2024-03-16T21:03:56.668+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match And [CsrfNotRequired [TRACE, HEAD, GET, OPTIONS], Not [Or [Mvc [pattern='/decrypt/**']]]]
2024-03-16T21:03:56.668+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (7/12)
2024-03-16T21:03:56.668+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2024-03-16T21:03:56.668+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking BasicAuthenticationFilter (8/12)
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.s.w.a.www.BasicAuthenticationFilter : Did not process authentication request since failed to find username and password in Basic Authorization header
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking RequestCacheAwareFilter (9/12)
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.s.w.s.HttpSessionRequestCache : matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (10/12)
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (11/12)
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (12/12)
2024-03-16T21:03:56.669+05:30 DEBUG 1432 --- [demo] [nio-8888-exec-7] o.s.security.web.FilterChainProxy : Secured POST /decrypt
2024-03-16T21:03:56.670+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.web.servlet.DispatcherServlet : POST "/decrypt", parameters={}, headers={masked} in DispatcherServlet 'dispatcherServlet'
2024-03-16T21:03:56.670+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'encryptionController'
2024-03-16T21:03:56.672+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.cloud.config.server.encryption.EncryptionController#decrypt(String, MediaType)
2024-03-16T21:03:56.672+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] m.m.a.RequestResponseBodyMethodProcessor : Read "application/json;charset=UTF-8" to ["encryptme"]
2024-03-16T21:03:56.673+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.web.method.HandlerMethod : Arguments: [encryptme, application/json]
2024-03-16T21:03:56.687+05:30 ERROR 1432 --- [demo] [nio-8888-exec-7] o.s.c.c.s.e.EncryptionController : Cannot decrypt key:application, value:encryptme, Please verify if encrypt.key is set correctly
Is it the expected behavior to validate only when username/password is sent via request headers and authentication is skipped if no authentication headers are sent via request??
Comment From: wilkinsona
Is it the expected behavior to validate only when username/password is sent via request headers and authentication is skipped
Yes. This is how Spring Security works and the behavior is shown in its TRACE logging:
2024-03-16T21:03:56.669+05:30 TRACE 1432 --- [demo] [nio-8888-exec-7] o.s.s.w.a.www.BasicAuthenticationFilter : Did not process authentication request since failed to find username and password in Basic Authorization header
This is out of Spring Boot's control. If you believe that things should behave differently, please open a Spring Security issue.