Add MultiFactorCondition.WEBAUTHN_REGISTERED
Closes gh-18923
This commit is contained in:
@@ -37,6 +37,19 @@ Spring Security behind the scenes knows which endpoint to go to depending on whi
|
||||
If the user logged in initially with their username and password, then Spring Security redirects to the One-Time-Token Login page.
|
||||
If the user logged in initially with a token, then Spring Security redirects to the Username/Password Login page.
|
||||
|
||||
[[mfa-when-webauthn-registered]]
|
||||
=== Conditionally Requiring MFA for WebAuthn Users
|
||||
|
||||
At times, you may want to conditionally require MFA only for users who have registered a WebAuthn credential (passkey).
|
||||
You can achieve this by specifying javadoc:org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication#when()[when = MultiFactorCondition.WEBAUTHN_REGISTERED].
|
||||
|
||||
include-code::./WebAuthnConditionConfiguration[tag=enable-mfa-webauthn,indent=0]
|
||||
|
||||
This configuration requires `FACTOR_WEBAUTHN` and `FACTOR_PASSWORD` only when the user has registered a passkey.
|
||||
It works by publishing a xref:./mfa.adoc#mfa-when-custom-conditions[`Customizer<AdditionalRequiredFactorsBuilder<Object>>`] that updates the xref:./mfa.adoc#programmatic-mfa[`withWhen`] method with the condition.
|
||||
|
||||
NOTE: This condition requires both a javadoc:org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository[] bean and a javadoc:org.springframework.security.web.webauthn.management.UserCredentialRepository[] bean to be published in order to determine if the user has registered a WebAuthn credential.
|
||||
|
||||
[[mfa-when-custom-conditions]]
|
||||
=== Custom MFA Conditions
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* https://github.com/spring-projects/spring-security/issues/18755[gh-18755] - Include `charset` in `WWW-Authenticate` header
|
||||
* Added xref:servlet/authorization/architecture.adoc#authz-conditional-authorization-manager[ConditionalAuthorizationManager]
|
||||
* Added `when` and `withWhen` conditions to `AuthorizationManagerFactories.multiFactor()` for xref:servlet/authentication/mfa.adoc#programmatic-mfa[Programmatic MFA]
|
||||
* Added `MultiFactorCondition.WEBAUTHN_REGISTERED` to `@EnableMultiFactorAuthentication(when = ...)` for xref:servlet/authentication/mfa.adoc#mfa-when-webauthn-registered[conditionally requiring MFA for WebAuthn Users]
|
||||
|
||||
== OAuth 2.0
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ dependencies {
|
||||
testImplementation project(':spring-security-oauth2-client')
|
||||
testImplementation project(':spring-security-oauth2-resource-server')
|
||||
testImplementation project(':spring-security-messaging')
|
||||
testImplementation project(':spring-security-webauthn')
|
||||
testImplementation 'com.squareup.okhttp3:mockwebserver'
|
||||
testImplementation libs.com.password4j.password4j
|
||||
testImplementation 'com.unboundid:unboundid-ldapsdk'
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.springframework.security.docs.servlet.authentication.mfawhencustomconditions;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
||||
import org.springframework.security.config.Customizer;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
class CustomizerAuthorizationManagerFactoryConfiguration {
|
||||
|
||||
// tag::customizer[]
|
||||
@Bean
|
||||
Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> additionalRequiredFactorsCustomizer() {
|
||||
return (builder) -> builder.when((auth) -> "admin".equals(auth.getName()));
|
||||
}
|
||||
// end::customizer[]
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.springframework.security.docs.servlet.authentication.mfawhenwebauthnregistered;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication;
|
||||
import org.springframework.security.config.annotation.authorization.MultiFactorCondition;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.core.authority.FactorGrantedAuthority;
|
||||
import org.springframework.security.web.webauthn.management.MapPublicKeyCredentialUserEntityRepository;
|
||||
import org.springframework.security.web.webauthn.management.MapUserCredentialRepository;
|
||||
import org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository;
|
||||
import org.springframework.security.web.webauthn.management.UserCredentialRepository;
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
// tag::enable-mfa-webauthn[]
|
||||
@EnableMultiFactorAuthentication(
|
||||
authorities = {
|
||||
FactorGrantedAuthority.PASSWORD_AUTHORITY,
|
||||
FactorGrantedAuthority.WEBAUTHN_AUTHORITY
|
||||
},
|
||||
when = MultiFactorCondition.WEBAUTHN_REGISTERED
|
||||
)
|
||||
public class WebAuthnConditionConfiguration {
|
||||
|
||||
@Bean
|
||||
public PublicKeyCredentialUserEntityRepository userEntityRepository() {
|
||||
return new MapPublicKeyCredentialUserEntityRepository();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserCredentialRepository userCredentialRepository() {
|
||||
return new MapUserCredentialRepository();
|
||||
}
|
||||
|
||||
}
|
||||
// end::enable-mfa-webauthn[]
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package org.springframework.security.kt.docs.servlet.authentication.mfawhencustomconditions
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.authorization.AuthorizationManagerFactories
|
||||
import org.springframework.security.config.Customizer
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
internal class CustomizerAuthorizationManagerFactoryConfiguration {
|
||||
|
||||
// tag::customizer[]
|
||||
@Bean
|
||||
fun additionalRequiredFactorsCustomizer(): Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Any>> {
|
||||
return Customizer { builder -> builder.`when` { auth -> "admin" == auth.name } }
|
||||
}
|
||||
// end::customizer[]
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.springframework.security.kt.docs.servlet.authentication.mfawhenwebauthnregistered
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication
|
||||
import org.springframework.security.config.annotation.authorization.MultiFactorCondition
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||
import org.springframework.security.core.authority.FactorGrantedAuthority
|
||||
import org.springframework.security.web.webauthn.management.MapPublicKeyCredentialUserEntityRepository
|
||||
import org.springframework.security.web.webauthn.management.MapUserCredentialRepository
|
||||
import org.springframework.security.web.webauthn.management.PublicKeyCredentialUserEntityRepository
|
||||
import org.springframework.security.web.webauthn.management.UserCredentialRepository
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
// tag::enable-mfa-webauthn[]
|
||||
@EnableMultiFactorAuthentication(
|
||||
authorities = [
|
||||
FactorGrantedAuthority.PASSWORD_AUTHORITY,
|
||||
FactorGrantedAuthority.WEBAUTHN_AUTHORITY
|
||||
],
|
||||
`when` = [MultiFactorCondition.WEBAUTHN_REGISTERED]
|
||||
)
|
||||
internal class WebAuthnConditionConfiguration {
|
||||
|
||||
@Bean
|
||||
fun userEntityRepository(): PublicKeyCredentialUserEntityRepository {
|
||||
return MapPublicKeyCredentialUserEntityRepository()
|
||||
}
|
||||
|
||||
@Bean
|
||||
fun userCredentialRepository(): UserCredentialRepository {
|
||||
return MapUserCredentialRepository()
|
||||
}
|
||||
|
||||
}
|
||||
// end::enable-mfa-webauthn[]
|
||||
Reference in New Issue
Block a user