diff --git a/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilter.java b/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilter.java index 9cee728a05..c2c80f19bd 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilter.java @@ -94,4 +94,21 @@ public final class DefaultResourcesFilter extends GenericFilterBean { new MediaType("text", "css", StandardCharsets.UTF_8)); } + /** + * Create an instance of {@link DefaultResourcesFilter} serving Spring Security's + * default webauthn javascript. + *

+ * The created {@link DefaultResourcesFilter} matches requests + * {@code HTTP GET /login/webauthn.js}, and returns the default webauthn javascript at + * {@code org/springframework/security/spring-security-webauthn.js} with content-type + * {@code text/javascript;charset=UTF-8}. This file is generated in the + * {@code spring-security-javascript} project. + * @return - + */ + public static DefaultResourcesFilter webauthn() { + return new DefaultResourcesFilter(AntPathRequestMatcher.antMatcher(HttpMethod.GET, "/login/webauthn.js"), + new ClassPathResource("org/springframework/security/spring-security-webauthn.js"), + new MediaType("text", "javascript", StandardCharsets.UTF_8)); + } + } diff --git a/web/src/test/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilterTests.java index fb6d75c3a1..e7d0eb2b23 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/ui/DefaultResourcesFilterTests.java @@ -16,6 +16,7 @@ package org.springframework.security.web.authentication.ui; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.test.web.servlet.MockMvc; @@ -33,27 +34,64 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. */ public class DefaultResourcesFilterTests { - private final DefaultResourcesFilter filter = DefaultResourcesFilter.css(); + @Nested + class CssFilter { - private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new Object()).addFilters(this.filter).build(); + private final DefaultResourcesFilter cssFilter = DefaultResourcesFilter.css(); + + private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new Object()) + .addFilters(this.cssFilter) + .build(); + + @Test + void doFilterThenRender() throws Exception { + this.mockMvc.perform(get("/default-ui.css")) + .andExpect(status().isOk()) + .andExpect(content().contentType("text/css;charset=UTF-8")) + .andExpect(content().string(containsString("body {"))); + } + + @Test + void doFilterWhenPathDoesNotMatchThenCallsThrough() throws Exception { + this.mockMvc.perform(get("/does-not-match")).andExpect(status().isNotFound()); + } + + @Test + void toStringPrintsPathAndResource() { + assertThat(this.cssFilter.toString()).isEqualTo( + "DefaultResourcesFilter [matcher=Ant [pattern='/default-ui.css', GET], resource=org/springframework/security/default-ui.css]"); + } - @Test - public void doFilterThenRender() throws Exception { - this.mockMvc.perform(get("/default-ui.css")) - .andExpect(status().isOk()) - .andExpect(content().contentType("text/css;charset=UTF-8")) - .andExpect(content().string(containsString("body {"))); } - @Test - public void doFilterWhenPathDoesNotMatchThenCallsThrough() throws Exception { - this.mockMvc.perform(get("/does-not-match")).andExpect(status().isNotFound()); - } + @Nested + class WebAuthnFilter { + + private final DefaultResourcesFilter webauthnFilter = DefaultResourcesFilter.webauthn(); + + private final MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new Object()) + .addFilters(this.webauthnFilter) + .build(); + + @Test + void doFilterThenRender() throws Exception { + this.mockMvc.perform(get("/login/webauthn.js")) + .andExpect(status().isOk()) + .andExpect(content().contentType("text/javascript;charset=UTF-8")) + .andExpect(content().string(containsString("async function authenticate("))); + } + + @Test + void doFilterWhenPathDoesNotMatchThenCallsThrough() throws Exception { + this.mockMvc.perform(get("/does-not-match")).andExpect(status().isNotFound()); + } + + @Test + void toStringPrintsPathAndResource() { + assertThat(this.webauthnFilter.toString()).isEqualTo( + "DefaultResourcesFilter [matcher=Ant [pattern='/login/webauthn.js', GET], resource=org/springframework/security/spring-security-webauthn.js]"); + } - @Test - void toStringPrintsPathAndResource() { - assertThat(this.filter.toString()).isEqualTo( - "DefaultResourcesFilter [matcher=Ant [pattern='/default-ui.css', GET], resource=org/springframework/security/default-ui.css]"); } }