|
|
|
@ -19,6 +19,8 @@ package org.springframework.security.config.annotation.web.configurers; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.nio.charset.StandardCharsets; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import com.fasterxml.jackson.databind.JsonNode; |
|
|
|
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper; |
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
import org.junit.jupiter.api.extension.ExtendWith; |
|
|
|
import org.junit.jupiter.api.extension.ExtendWith; |
|
|
|
|
|
|
|
|
|
|
|
@ -52,6 +54,8 @@ import static org.mockito.ArgumentMatchers.any; |
|
|
|
import static org.mockito.BDDMockito.given; |
|
|
|
import static org.mockito.BDDMockito.given; |
|
|
|
import static org.mockito.BDDMockito.willAnswer; |
|
|
|
import static org.mockito.BDDMockito.willAnswer; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
|
|
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; |
|
|
|
|
|
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; |
|
|
|
@ -127,6 +131,42 @@ public class WebAuthnConfigurerTests { |
|
|
|
.hasSize(1); |
|
|
|
.hasSize(1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
void webauthnWhenConfiguredDefaultsRpNameToRpId() throws Exception { |
|
|
|
|
|
|
|
ObjectMapper mapper = new ObjectMapper(); |
|
|
|
|
|
|
|
this.spring.register(DefaultWebauthnConfiguration.class).autowire(); |
|
|
|
|
|
|
|
String response = this.mvc |
|
|
|
|
|
|
|
.perform(post("/webauthn/register/options").with(csrf()) |
|
|
|
|
|
|
|
.with(authentication(new TestingAuthenticationToken("test", "ignored", "ROLE_user")))) |
|
|
|
|
|
|
|
.andExpect(status().is2xxSuccessful()) |
|
|
|
|
|
|
|
.andReturn() |
|
|
|
|
|
|
|
.getResponse() |
|
|
|
|
|
|
|
.getContentAsString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JsonNode parsedResponse = mapper.readTree(response); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(parsedResponse.get("rp").get("id").asText()).isEqualTo("example.com"); |
|
|
|
|
|
|
|
assertThat(parsedResponse.get("rp").get("name").asText()).isEqualTo("example.com"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
void webauthnWhenRpNameConfiguredUsesRpName() throws Exception { |
|
|
|
|
|
|
|
ObjectMapper mapper = new ObjectMapper(); |
|
|
|
|
|
|
|
this.spring.register(CustomRpNameWebauthnConfiguration.class).autowire(); |
|
|
|
|
|
|
|
String response = this.mvc |
|
|
|
|
|
|
|
.perform(post("/webauthn/register/options").with(csrf()) |
|
|
|
|
|
|
|
.with(authentication(new TestingAuthenticationToken("test", "ignored", "ROLE_user")))) |
|
|
|
|
|
|
|
.andExpect(status().is2xxSuccessful()) |
|
|
|
|
|
|
|
.andReturn() |
|
|
|
|
|
|
|
.getResponse() |
|
|
|
|
|
|
|
.getContentAsString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JsonNode parsedResponse = mapper.readTree(response); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(parsedResponse.get("rp").get("id").asText()).isEqualTo("example.com"); |
|
|
|
|
|
|
|
assertThat(parsedResponse.get("rp").get("name").asText()).isEqualTo("Test RP Name"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
public void webauthnWhenConfiguredAndFormLoginThenDoesServesJavascript() throws Exception { |
|
|
|
public void webauthnWhenConfiguredAndFormLoginThenDoesServesJavascript() throws Exception { |
|
|
|
this.spring.register(FormLoginAndNoDefaultRegistrationPageConfiguration.class).autowire(); |
|
|
|
this.spring.register(FormLoginAndNoDefaultRegistrationPageConfiguration.class).autowire(); |
|
|
|
@ -300,7 +340,27 @@ public class WebAuthnConfigurerTests { |
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
@Bean |
|
|
|
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
|
|
|
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
|
|
|
return http.formLogin(Customizer.withDefaults()).webAuthn(Customizer.withDefaults()).build(); |
|
|
|
return http.formLogin(Customizer.withDefaults()) |
|
|
|
|
|
|
|
.webAuthn((webauthn) -> webauthn.rpId("example.com")) |
|
|
|
|
|
|
|
.build(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
|
|
|
@EnableWebSecurity |
|
|
|
|
|
|
|
static class CustomRpNameWebauthnConfiguration { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
UserDetailsService userDetailsService() { |
|
|
|
|
|
|
|
return new InMemoryUserDetailsManager(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
|
|
|
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { |
|
|
|
|
|
|
|
return http.formLogin(Customizer.withDefaults()) |
|
|
|
|
|
|
|
.webAuthn((webauthn) -> webauthn.rpId("example.com").rpName("Test RP Name")) |
|
|
|
|
|
|
|
.build(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|