Support Customizer<AdditionalRequiredFactorsBuilder<Object>>>
Closes gh-18922
This commit is contained in:
+9
-3
@@ -16,13 +16,16 @@
|
|||||||
|
|
||||||
package org.springframework.security.config.annotation.authorization;
|
package org.springframework.security.config.annotation.authorization;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ImportAware;
|
import org.springframework.context.annotation.ImportAware;
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
import org.springframework.core.type.AnnotationMetadata;
|
||||||
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder;
|
||||||
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
import org.springframework.security.authorization.DefaultAuthorizationManagerFactory;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses {@link EnableMultiFactorAuthentication} to configure a
|
* Uses {@link EnableMultiFactorAuthentication} to configure a
|
||||||
@@ -37,10 +40,13 @@ class AuthorizationManagerFactoryConfiguration implements ImportAware {
|
|||||||
private String[] authorities;
|
private String[] authorities;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
DefaultAuthorizationManagerFactory authorizationManagerFactory() {
|
DefaultAuthorizationManagerFactory authorizationManagerFactory(
|
||||||
AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object> builder = AuthorizationManagerFactories
|
List<Customizer<AdditionalRequiredFactorsBuilder<Object>>> additionalRequiredFactorsCustomizers) {
|
||||||
.multiFactor()
|
AdditionalRequiredFactorsBuilder<Object> builder = AuthorizationManagerFactories.multiFactor()
|
||||||
.requireFactors(this.authorities);
|
.requireFactors(this.authorities);
|
||||||
|
for (Customizer<AdditionalRequiredFactorsBuilder<Object>> customizer : additionalRequiredFactorsCustomizers) {
|
||||||
|
customizer.customize(builder);
|
||||||
|
}
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
@@ -45,6 +45,19 @@ import org.springframework.security.authorization.DefaultAuthorizationManagerFac
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* You can also publish one or more
|
||||||
|
* {@code Customizer<AdditionalRequiredFactorsBuilder<Object>>} beans to further customize
|
||||||
|
* the {@link DefaultAuthorizationManagerFactory}. For example, conditionally applying MFA
|
||||||
|
* for specific users:
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* @Bean
|
||||||
|
* Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> additionalRequiredFactorsCustomizer() {
|
||||||
|
* return (builder) -> builder.when((auth) -> "admin".equals(auth.getName()));
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
* NOTE: At this time reactive applications do not support MFA and thus are not impacted.
|
* NOTE: At this time reactive applications do not support MFA and thus are not impacted.
|
||||||
* This will likely be enhanced in the future.
|
* This will likely be enhanced in the future.
|
||||||
*
|
*
|
||||||
|
|||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-present the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.config.annotation.authorization;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.core.authority.FactorGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link EnableMultiFactorAuthentication} with
|
||||||
|
* {@link Customizer}<{@link AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder}>.
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration(classes = EnableMultiFactorAuthenticationCustomizerTests.ConfigWithCustomizer.class)
|
||||||
|
class EnableMultiFactorAuthenticationCustomizerTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "user", authorities = "ROLE_USER")
|
||||||
|
void whenCustomizerAppliedThenConditionalMfaUsed() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "admin", authorities = "ROLE_USER")
|
||||||
|
void whenCustomizerAppliedAndConditionTrueThenMfaRequired() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "admin", authorities = { "ROLE_USER", FactorGrantedAuthority.PASSWORD_AUTHORITY,
|
||||||
|
FactorGrantedAuthority.OTT_AUTHORITY })
|
||||||
|
void whenCustomizerAppliedAndConditionTrueWithMfaThenAuthorized() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
@Configuration
|
||||||
|
@EnableMultiFactorAuthentication(
|
||||||
|
authorities = { FactorGrantedAuthority.OTT_AUTHORITY, FactorGrantedAuthority.PASSWORD_AUTHORITY })
|
||||||
|
static class ConfigWithCustomizer {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> additionalRequiredFactorsCustomizer() {
|
||||||
|
return (builder) -> builder.when((auth) -> "admin".equals(auth.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MockMvc mvc(WebApplicationContext context) {
|
||||||
|
return MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
UserDetailsService userDetailsService() {
|
||||||
|
UserDetails user = User.withDefaultPasswordEncoder()
|
||||||
|
.username("user")
|
||||||
|
.password("password")
|
||||||
|
.roles("USER")
|
||||||
|
.build();
|
||||||
|
UserDetails admin = User.withDefaultPasswordEncoder()
|
||||||
|
.username("admin")
|
||||||
|
.password("password")
|
||||||
|
.roles("USER")
|
||||||
|
.build();
|
||||||
|
return new InMemoryUserDetailsManager(user, admin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
static class OkController {
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
String ok() {
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2004-present the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.security.config.annotation.authorization;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
||||||
|
import org.springframework.security.config.Customizer;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.core.authority.FactorGrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.User;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||||
|
import org.springframework.security.test.context.support.WithMockUser;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link EnableMultiFactorAuthentication} with multiple
|
||||||
|
* {@link Customizer}<{@link AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder}>
|
||||||
|
* beans.
|
||||||
|
*/
|
||||||
|
@ExtendWith(SpringExtension.class)
|
||||||
|
@WebAppConfiguration
|
||||||
|
@ContextConfiguration(
|
||||||
|
classes = EnableMultiFactorAuthenticationMultipleCustomizersTests.ConfigWithMultipleCustomizers.class)
|
||||||
|
class EnableMultiFactorAuthenticationMultipleCustomizersTests {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
MockMvc mvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "user", authorities = "ROLE_USER")
|
||||||
|
void whenCustomizerAppliedThenConditionalMfaUsed() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "admin", authorities = "ROLE_USER")
|
||||||
|
void whenCustomizersAppliedAndConditionTrueThenMfaRequired() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "admin", authorities = { "ROLE_USER", FactorGrantedAuthority.PASSWORD_AUTHORITY,
|
||||||
|
FactorGrantedAuthority.OTT_AUTHORITY })
|
||||||
|
void whenCustomizersAppliedAndConditionTrueWithMfaThenAuthorized() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@WithMockUser(username = "manager", authorities = "ROLE_USER")
|
||||||
|
void whenSecondCustomizerAppliedAndConditionTrueThenMfaRequired() throws Exception {
|
||||||
|
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
@Configuration
|
||||||
|
@EnableMultiFactorAuthentication(
|
||||||
|
authorities = { FactorGrantedAuthority.OTT_AUTHORITY, FactorGrantedAuthority.PASSWORD_AUTHORITY })
|
||||||
|
static class ConfigWithMultipleCustomizers {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(1)
|
||||||
|
Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> adminCustomizer() {
|
||||||
|
return (builder) -> builder.withWhen(
|
||||||
|
(current) -> (auth) -> "admin".equals(auth.getName()) || (current != null && current.test(auth)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Order(2)
|
||||||
|
Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> managerCustomizer() {
|
||||||
|
return (builder) -> builder.withWhen(
|
||||||
|
(current) -> (auth) -> "manager".equals(auth.getName()) || (current != null && current.test(auth)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
MockMvc mvc(WebApplicationContext context) {
|
||||||
|
return MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
UserDetailsService userDetailsService() {
|
||||||
|
UserDetails user = User.withDefaultPasswordEncoder()
|
||||||
|
.username("user")
|
||||||
|
.password("password")
|
||||||
|
.roles("USER")
|
||||||
|
.build();
|
||||||
|
UserDetails admin = User.withDefaultPasswordEncoder()
|
||||||
|
.username("admin")
|
||||||
|
.password("password")
|
||||||
|
.roles("USER")
|
||||||
|
.build();
|
||||||
|
UserDetails manager = User.withDefaultPasswordEncoder()
|
||||||
|
.username("manager")
|
||||||
|
.password("password")
|
||||||
|
.roles("USER")
|
||||||
|
.build();
|
||||||
|
return new InMemoryUserDetailsManager(user, admin, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
static class OkController {
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
String ok() {
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -37,6 +37,14 @@ 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 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.
|
If the user logged in initially with a token, then Spring Security redirects to the Username/Password Login page.
|
||||||
|
|
||||||
|
[[mfa-when-custom-conditions]]
|
||||||
|
=== Custom MFA Conditions
|
||||||
|
|
||||||
|
You can also publish one or more `Customizer<AdditionalRequiredFactorsBuilder<Object>>` beans to customize the factory created by `@EnableMultiFactorAuthentication`.
|
||||||
|
For example, you can conditionally apply MFA for specific users:
|
||||||
|
|
||||||
|
include-code::./CustomizerAuthorizationManagerFactoryConfiguration[tag=customizer,indent=0]
|
||||||
|
|
||||||
[[authorization-manager-factory]]
|
[[authorization-manager-factory]]
|
||||||
== AuthorizationManagerFactory
|
== AuthorizationManagerFactory
|
||||||
|
|
||||||
@@ -48,6 +56,7 @@ The `AuthorizationManagerFactory` Bean below is what is published in the previou
|
|||||||
|
|
||||||
include-code::./UseAuthorizationManagerFactoryConfiguration[tag=authorizationManagerFactoryBean,indent=0]
|
include-code::./UseAuthorizationManagerFactoryConfiguration[tag=authorizationManagerFactoryBean,indent=0]
|
||||||
|
|
||||||
|
|
||||||
[[selective-mfa]]
|
[[selective-mfa]]
|
||||||
== Selectively Requiring MFA
|
== Selectively Requiring MFA
|
||||||
|
|
||||||
|
|||||||
+7
@@ -47,6 +47,13 @@ class UseAuthorizationManagerFactoryConfiguration {
|
|||||||
}
|
}
|
||||||
// end::authorizationManagerFactoryBean[]
|
// end::authorizationManagerFactoryBean[]
|
||||||
|
|
||||||
|
// tag::customizer[]
|
||||||
|
@Bean
|
||||||
|
Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object>> additionalRequiredFactorsCustomizer() {
|
||||||
|
return (builder) -> builder.when((auth) -> "admin".equals(auth.getName()));
|
||||||
|
}
|
||||||
|
// end::customizer[]
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
UserDetailsService userDetailsService() {
|
UserDetailsService userDetailsService() {
|
||||||
return new InMemoryUserDetailsManager(
|
return new InMemoryUserDetailsManager(
|
||||||
|
|||||||
+1
@@ -2,6 +2,7 @@ package org.springframework.security.docs.servlet.authentication.emfa;
|
|||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManagerFactories;
|
||||||
import org.springframework.security.config.Customizer;
|
import org.springframework.security.config.Customizer;
|
||||||
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication;
|
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
|||||||
+8
@@ -4,6 +4,7 @@ import org.springframework.context.annotation.Bean
|
|||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.security.authorization.AuthorizationManagerFactories
|
import org.springframework.security.authorization.AuthorizationManagerFactories
|
||||||
import org.springframework.security.authorization.AuthorizationManagerFactory
|
import org.springframework.security.authorization.AuthorizationManagerFactory
|
||||||
|
import org.springframework.security.config.Customizer
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.invoke
|
import org.springframework.security.config.annotation.web.invoke
|
||||||
@@ -47,6 +48,13 @@ internal class UseAuthorizationManagerFactoryConfiguration {
|
|||||||
}
|
}
|
||||||
// end::authorizationManagerFactoryBean[]
|
// end::authorizationManagerFactoryBean[]
|
||||||
|
|
||||||
|
// tag::customizer[]
|
||||||
|
@Bean
|
||||||
|
fun additionalRequiredFactorsCustomizer(): Customizer<AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Any>> {
|
||||||
|
return Customizer { builder -> builder.`when` { auth -> "admin" == auth.name } }
|
||||||
|
}
|
||||||
|
// end::customizer[]
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@Bean
|
@Bean
|
||||||
fun userDetailsService(): UserDetailsService {
|
fun userDetailsService(): UserDetailsService {
|
||||||
|
|||||||
+2
@@ -2,6 +2,8 @@ package org.springframework.security.kt.docs.servlet.authentication.emfa
|
|||||||
|
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.security.authorization.AuthorizationManagerFactories
|
||||||
|
import org.springframework.security.config.Customizer
|
||||||
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication
|
import org.springframework.security.config.annotation.authorization.EnableMultiFactorAuthentication
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
|||||||
Reference in New Issue
Block a user