spring-projects / spring-projects/spring-security
Endpoint filters should be reachable when using `spring.mvc.servlet.path`
@jzheaux is already working on this.
Since Dec 4, 2023.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Expected Behavior
DefaultLoginPageGeneratingFilter supports manual path prefix, such as ${spring.mvc.servlet.path} prefix.
As the issue #14188 that I submitted, DefaultLoginPageGeneratingFilter doesn't work while ${spring.mvc.servlet.path} property is not '/'. due to DefaultLoginPageGeneratingFilter only process fixed url path: /login.
My current solution is to hack FormLoginConfigurer class, like bellow codes:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception
{
// Management ENdpoints Base Path is '/__admin'
String endpointsWebBasePath = AppConfigHolder.getManagementEndpointsBasePath();
if(GeneralHelper.isStrEmpty(endpointsWebBasePath) || endpointsWebBasePath.equals("/"))
http.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests.anyRequest().permitAll()).build();
else
{
// Spring MVC Servlet Path is '/aaa'
String mvcServletPath = AppConfigHolder.getSpringMvcServletPath();
// prefix == '/aaa'
String prefix = (GeneralHelper.isStrNotEmpty(mvcServletPath) && !mvcServletPath.equals("/")) ? mvcServletPath : "";
// managementBasePath == "/aaa/__admin/**"
String managementBasePath = prefix + endpointsWebBasePath + "/**";
http
.authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests
.requestMatchers(AntPathRequestMatcher.antMatcher(managementBasePath)).authenticated()
.requestMatchers(AntPathRequestMatcher.antMatcher("/**")).permitAll())
.csrf((csrf) -> csrf.disable())
.httpBasic(Customizer.withDefaults())
.formLogin(new Customizer<FormLoginConfigurer<HttpSecurity>>()
{
@Override
public void customize(FormLoginConfigurer<HttpSecurity> cfg)
{
if(GeneralHelper.isStrEmpty(prefix))
return;
// if prefix == '/aaa', then set login page to '/aaa/login'
cfg.loginPage(prefix + DefaultLoginPageGeneratingFilter.DEFAULT_LOGIN_PAGE_URL);
try
{
final String FIELD_NAME = "customLoginPage";
Field customLoginPage = AbstractAuthenticationFilterConfigurer.class.getDeclaredField(FIELD_NAME);
// Because loginPage() set the field 'customLoginPage' of FormLoginConfigurer to true automatically, DefaultLoginPageGeneratingFilter would be ignored.
// Cheat FormLoginConfigurer and reset it's 'customLoginPage' to false.
// Ugly, but work fine.
customLoginPage.setAccessible(true);
customLoginPage.set(cfg, false);
}
catch(Exception e)
{
throw new RuntimeException("set actuator login page fail", e);
}
}
});
}
return http.build();
}
Conclusion
FormLoginConfigurer provides another loginPage() like loginPage(String loginPage, boolean customLoginPage) to replace the hack code above, and then DefaultLoginPageGeneratingFilter would supports manual path prefix.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.