Describe the bug I am using spring security httpBasic and formLogin with rememberMe functionality. My goal was to replace FormData with JSON as payload in request for POST /login.
To Reproduce It seems that even if I change defaults url like this:
http.formLogin()
.loginPage("/auth/login")
.loginProcessingUrl("/auth/login")
.permitAll()
and then put instance of UsernamePasswordAuthenticationFilter into filter chain, like this:
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter::class.java)
Spring security completle ignores changed url from /auth/login and still works /login, even if specified differently.
Full configuration looks like this:
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
return http.httpBasic(Customizer.withDefaults())
.cors()
.configurationSource { CorsConfiguration().applyPermitDefaultValues() }
.and()
.rememberMe()
.tokenRepository(persistentTokenRepository(dataSource))
.alwaysRemember(true)
.and()
.exceptionHandling()
.authenticationEntryPoint(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.formLogin()
.loginPage("/auth/login")
.loginProcessingUrl("/auth/login")
.permitAll()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "$ADS_API/**").permitAll()
.antMatchers(
"/auth/**",
"/locate").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.apply(Test(successHandler, failureHandler))
.and().build()
}
@Bean
fun authManager(httpSecurity: HttpSecurity): AuthenticationManager {
return httpSecurity.getSharedObject(AuthenticationManagerBuilder::class.java)
.userDetailsService<UserDetailsService>(userDetailService)
.passwordEncoder(passwordEncoder)
.and()
.authenticationProvider(authenticationProvider)
.build()
}
And Test configurer used for appying my custom filter
@Component
class Test(
private val successHandler: RestAuthenticationSuccessHandler,
private val failureHandler: RestAuthenticationFailureHandler,
) : AbstractHttpConfigurer<Test, HttpSecurity>() {
override fun configure(http: HttpSecurity) {
val authenticationManager = http.getSharedObject(AuthenticationManager::class.java)
val rememberMeServices = http.getSharedObject(RememberMeServices::class.java)
val filter = JsonObjectAuthenticationFilter(authenticationManager)
filter.setAuthenticationSuccessHandler(successHandler)
filter.setAuthenticationFailureHandler(failureHandler)
filter.rememberMeServices = rememberMeServices
http.addFilterBefore(filter, UsernamePasswordAuthenticationFilter::class.java)
}
}
My custom filter:
class JsonObjectAuthenticationFilter(authenticationManager: AuthenticationManager) : UsernamePasswordAuthenticationFilter(authenticationManager) {
private val objectMapper: ObjectMapper = ObjectMapper().registerKotlinModule()
override fun attemptAuthentication(request: HttpServletRequest, response: HttpServletResponse): Authentication {
try {
val reader = request.reader
val sb = StringBuilder()
var line: String? = reader.readLine()
while (line != null) {
sb.append(line)
line = reader.readLine()
}
val authRequest: LoginCredentials = objectMapper.readValue(sb.toString(), LoginCredentials::class.java)
val token = UsernamePasswordAuthenticationToken.unauthenticated(
authRequest.email, authRequest.password
)
setDetails(request, token)
return this.authenticationManager.authenticate(token);
} catch (e: IOException) {
throw IllegalArgumentException(e.message)
}
}
}
Expected behavior Seems like spring-security is completly ignoring my change of urls and still listens on /login instead of /auth/login. I would expect that in such situation change to configuration is applied.
Comment From: sjohnr
Hi @hadson172, thanks for reaching out!
What you're describing is a result of the way the Spring Security DSL works. When you configure Spring Security via the DSL for something like form login (e.g. http.formLogin()), you are configuring a filter that is added to the filter chain on your behalf. Methods in the configurer such as loginPage(...) affect the filter that is built internally. Take a look at AbstractAuthenticationFilterConfigurer#configure for example.
When you build your own filter, you are responsible for configuring it manually with Java code and the DSL will not affect it in any way, which is by design.
I'm going to close this issue as answered. If you have further questions, please open a stackoverflow question and link to it here (so that others can find it) and I'll be happy to take a look.
Comment From: chengweng
你应该定义一个AuthenticationFilterConfigurer 配置类,因为你用formLogin()来的话他默认初始化一个 FormLoginConfigurer
而FormLoginConfigurer里面会对UsernamePasswordAuthenticationFilter进行初始化配置,而不是你自己定义的UsernamePasswordAuthenticationFilter
我不清楚这是不是security框架为了安全这样考虑,所以这样做的,导致自定义的UsernamePasswordAuthenticationFilter会无法正常初始化获取HttpSecurity里面的配置