|  | 
| 1 | 1 | /* | 
| 2 |  | - * Copyright 2002-2024 the original author or authors. | 
|  | 2 | + * Copyright 2002-2025 the original author or authors. | 
| 3 | 3 |  * | 
| 4 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 5 | 5 |  * you may not use this file except in compliance with the License. | 
|  | 
| 21 | 21 | import org.junit.jupiter.api.Test; | 
| 22 | 22 | import org.junit.jupiter.api.extension.ExtendWith; | 
| 23 | 23 | 
 | 
|  | 24 | +import org.springframework.beans.BeansException; | 
| 24 | 25 | import org.springframework.beans.factory.annotation.Autowired; | 
|  | 26 | +import org.springframework.beans.factory.config.BeanPostProcessor; | 
| 25 | 27 | import org.springframework.context.annotation.Bean; | 
| 26 | 28 | import org.springframework.context.annotation.Configuration; | 
| 27 | 29 | import org.springframework.security.config.Customizer; | 
|  | 
| 34 | 36 | import org.springframework.security.web.FilterChainProxy; | 
| 35 | 37 | import org.springframework.security.web.SecurityFilterChain; | 
| 36 | 38 | import org.springframework.security.web.authentication.ui.DefaultResourcesFilter; | 
|  | 39 | +import org.springframework.security.web.webauthn.authentication.HttpSessionPublicKeyCredentialRequestOptionsRepository; | 
|  | 40 | +import org.springframework.security.web.webauthn.authentication.PublicKeyCredentialRequestOptionsFilter; | 
|  | 41 | +import org.springframework.security.web.webauthn.authentication.PublicKeyCredentialRequestOptionsRepository; | 
|  | 42 | +import org.springframework.security.web.webauthn.authentication.WebAuthnAuthenticationFilter; | 
|  | 43 | +import org.springframework.security.web.webauthn.registration.HttpSessionPublicKeyCredentialCreationOptionsRepository; | 
|  | 44 | +import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsFilter; | 
|  | 45 | +import org.springframework.security.web.webauthn.registration.PublicKeyCredentialCreationOptionsRepository; | 
|  | 46 | +import org.springframework.security.web.webauthn.registration.WebAuthnRegistrationFilter; | 
| 37 | 47 | import org.springframework.test.web.servlet.MockMvc; | 
| 38 | 48 | 
 | 
| 39 | 49 | import static org.assertj.core.api.Assertions.assertThat; | 
| @@ -126,6 +136,67 @@ public void webauthnWhenConfiguredAndNoDefaultRegistrationPageThenDoesNotServeJa | 
| 126 | 136 | 		this.mvc.perform(get("/login/webauthn.js")).andExpect(status().isNotFound()); | 
| 127 | 137 | 	} | 
| 128 | 138 | 
 | 
|  | 139 | +	@Test | 
|  | 140 | +	public void configWebauthn() { | 
|  | 141 | +		this.spring.register(WebauthnFilterConfiguration.class).autowire(); | 
|  | 142 | +		assertThat(WebauthnFilterConfiguration.count).isEqualTo(4); | 
|  | 143 | +	} | 
|  | 144 | + | 
|  | 145 | +	@Configuration | 
|  | 146 | +	@EnableWebSecurity | 
|  | 147 | +	static class WebauthnFilterConfiguration { | 
|  | 148 | + | 
|  | 149 | +		static int count = 0; | 
|  | 150 | + | 
|  | 151 | +		@Bean | 
|  | 152 | +		PublicKeyCredentialRequestOptionsRepository requestOptionsRepository() { | 
|  | 153 | +			return new HttpSessionPublicKeyCredentialRequestOptionsRepository(); | 
|  | 154 | +		} | 
|  | 155 | + | 
|  | 156 | +		@Bean | 
|  | 157 | +		PublicKeyCredentialCreationOptionsRepository creationOptionsRepository() { | 
|  | 158 | +			return new HttpSessionPublicKeyCredentialCreationOptionsRepository(); | 
|  | 159 | +		} | 
|  | 160 | + | 
|  | 161 | +		@Bean | 
|  | 162 | +		static BeanPostProcessor beanPostProcessor(PublicKeyCredentialRequestOptionsRepository requestOptionsRepository, | 
|  | 163 | +				PublicKeyCredentialCreationOptionsRepository creationOptionsRepository) { | 
|  | 164 | +			return new BeanPostProcessor() { | 
|  | 165 | +				@Override | 
|  | 166 | +				public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { | 
|  | 167 | +					if (bean instanceof WebAuthnAuthenticationFilter filter) { | 
|  | 168 | +						filter.setRequestOptionsRepository(requestOptionsRepository); | 
|  | 169 | +						count++; | 
|  | 170 | +					} | 
|  | 171 | +					else if (bean instanceof WebAuthnRegistrationFilter filter) { | 
|  | 172 | +						filter.setCreationOptionsRepository(creationOptionsRepository); | 
|  | 173 | +						count++; | 
|  | 174 | +					} | 
|  | 175 | +					else if (bean instanceof PublicKeyCredentialCreationOptionsFilter filter) { | 
|  | 176 | +						filter.setCreationOptionsRepository(creationOptionsRepository); | 
|  | 177 | +						count++; | 
|  | 178 | +					} | 
|  | 179 | +					else if (bean instanceof PublicKeyCredentialRequestOptionsFilter filter) { | 
|  | 180 | +						filter.setRequestOptionsRepository(requestOptionsRepository); | 
|  | 181 | +						count++; | 
|  | 182 | +					} | 
|  | 183 | +					return bean; | 
|  | 184 | +				} | 
|  | 185 | +			}; | 
|  | 186 | +		} | 
|  | 187 | + | 
|  | 188 | +		@Bean | 
|  | 189 | +		UserDetailsService userDetailsService() { | 
|  | 190 | +			return new InMemoryUserDetailsManager(); | 
|  | 191 | +		} | 
|  | 192 | + | 
|  | 193 | +		@Bean | 
|  | 194 | +		SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { | 
|  | 195 | +			return http.webAuthn(Customizer.withDefaults()).build(); | 
|  | 196 | +		} | 
|  | 197 | + | 
|  | 198 | +	} | 
|  | 199 | + | 
| 129 | 200 | 	@Configuration | 
| 130 | 201 | 	@EnableWebSecurity | 
| 131 | 202 | 	static class DefaultWebauthnConfiguration { | 
|  | 
0 commit comments