1
0
mirror of synced 2026-09-12 12:15:13 +00:00

Ignore Chrome DevTools well-known probe in default RequestCache

Chrome DevTools itself (not the loaded page, and not the user)
requests /.well-known/appspecific/com.chrome.devtools.json when
DevTools is open against a page, as part of the Automatic Workspace
Folders feature, to map a local project folder for live source
editing. This request is tooling-driven, not user navigation, so it
should never be able to become the URL a user is redirected to after
authenticating.

Closes gh-19694
This commit is contained in:
Robert Winch
2026-09-09 14:12:56 -05:00
parent bf30738840
commit 0ca2c39244
6 changed files with 46 additions and 3 deletions
@@ -188,7 +188,10 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
"/browserconfig.xml",
// Chrome DevTools itself (not the page, not the user) requests this to
// discover an Automatic Workspace Folder mapping for local source editing
"/.well-known/appspecific/com.chrome.devtools.json" };
private RequestMatcher getIgnoredBackgroundRequestMatcher() {
List<RequestMatcher> matchers = new ArrayList<>();
@@ -200,6 +200,20 @@ public class RequestCacheConfigurerTests {
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@Test
public void getWhenBookmarkedUrlIsChromeDevtoolsJsonThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/.well-known/appspecific/com.chrome.devtools.json"))
.andExpect(redirectedUrl("/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores /.well-known/appspecific/com.chrome.devtools.json
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
// SEC-2321
@Test
public void getWhenBookmarkedRequestIsApplicationJsonThenPostAuthenticationRedirectsToRoot() throws Exception {
@@ -174,7 +174,10 @@ public class CookieServerRequestCache implements ServerRequestCache {
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
"/browserconfig.xml",
// Chrome DevTools itself (not the page, not the user) requests this to
// discover an Automatic Workspace Folder mapping for local source editing
"/.well-known/appspecific/com.chrome.devtools.json" };
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
ServerWebExchangeMatcher get = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/**");
@@ -174,7 +174,10 @@ public class WebSessionServerRequestCache implements ServerRequestCache {
"/manifest.json", "/manifest.webmanifest",
// Legacy IE11/Edge fetch browserconfig.xml in the background to
// configure pinned-site tiles
"/browserconfig.xml" };
"/browserconfig.xml",
// Chrome DevTools itself (not the page, not the user) requests this to
// discover an Automatic Workspace Folder mapping for local source editing
"/.well-known/appspecific/com.chrome.devtools.json" };
private static ServerWebExchangeMatcher createDefaultRequestMatcher() {
ServerWebExchangeMatcher get = ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/**");
@@ -131,6 +131,16 @@ public class CookieServerRequestCacheTests {
assertThat(cookies).isEmpty();
}
@Test
public void saveRequestWhenGetRequestChromeDevtoolsJsonThenNoCookie() {
MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/.well-known/appspecific/com.chrome.devtools.json")
.accept(MediaType.TEXT_HTML));
this.cache.saveRequest(exchange).block();
MultiValueMap<String, ResponseCookie> cookies = exchange.getResponse().getCookies();
assertThat(cookies).isEmpty();
}
@Test
public void saveRequestWhenPostRequestThenNoCookie() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/secured/"));
@@ -122,6 +122,16 @@ public class WebSessionServerRequestCacheTests {
assertThat(saved).isNull();
}
@Test
public void saveRequestGetRequestWhenChromeDevtoolsJsonThenNotFound() {
MockServerWebExchange exchange = MockServerWebExchange
.from(MockServerHttpRequest.get("/.well-known/appspecific/com.chrome.devtools.json")
.accept(MediaType.TEXT_HTML));
this.cache.saveRequest(exchange).block();
URI saved = this.cache.getRedirectUri(exchange).block();
assertThat(saved).isNull();
}
@Test
public void saveRequestGetRequestWhenPostThenNotFound() {
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.post("/secured/"));