diff --git a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParser.java index 0439549e28..a4d79280ac 100644 --- a/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 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. @@ -57,6 +57,8 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition private static final String ATT_ERASE_CREDENTIALS = "erase-credentials"; + private static final String AUTHENTICATION_EVENT_PUBLISHER_BEAN_NAME = "defaultAuthenticationEventPublisher"; + @Override public BeanDefinition parse(Element element, ParserContext pc) { String id = element.getAttribute("id"); @@ -86,11 +88,15 @@ public class AuthenticationManagerBeanDefinitionParser implements BeanDefinition if ("false".equals(element.getAttribute(ATT_ERASE_CREDENTIALS))) { providerManagerBldr.addPropertyValue("eraseCredentialsAfterAuthentication", false); } - // Add the default event publisher - BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class); - String pubId = pc.getReaderContext().generateBeanName(publisher); - pc.registerBeanComponent(new BeanComponentDefinition(publisher, pubId)); - providerManagerBldr.addPropertyReference("authenticationEventPublisher", pubId); + + if (!pc.getRegistry().containsBeanDefinition(AUTHENTICATION_EVENT_PUBLISHER_BEAN_NAME)) { + // Add the default event publisher to the context + BeanDefinition publisher = new RootBeanDefinition(DefaultAuthenticationEventPublisher.class); + pc.registerBeanComponent(new BeanComponentDefinition(publisher, AUTHENTICATION_EVENT_PUBLISHER_BEAN_NAME)); + } + + providerManagerBldr.addPropertyReference("authenticationEventPublisher", + AUTHENTICATION_EVENT_PUBLISHER_BEAN_NAME); pc.registerBeanComponent(new BeanComponentDefinition(providerManagerBldr.getBeanDefinition(), id)); if (StringUtils.hasText(alias)) { pc.getRegistry().registerAlias(id, alias); diff --git a/config/src/test/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParserTests.java index a7654277b1..c71f7917a0 100644 --- a/config/src/test/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/authentication/AuthenticationManagerBeanDefinitionParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2021 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. @@ -25,6 +25,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; import org.springframework.security.authentication.ProviderManager; @@ -54,6 +55,17 @@ public class AuthenticationManagerBeanDefinitionParserTests { + ""; // @formatter:on + // Issue #7282 + // @formatter:off + private static final String CONTEXT_MULTI = "" + + " " + + " " + + " " + + " " + + " " + + ""; + // @formatter:on + @Rule public final SpringTestRule spring = new SpringTestRule(); @@ -64,6 +76,18 @@ public class AuthenticationManagerBeanDefinitionParserTests { assertThat(context.getBeansOfType(AuthenticationProvider.class)).hasSize(1); } + @Test + public void eventPublishersAreRegisteredAsTopLevelBeans() { + ConfigurableApplicationContext context = this.spring.context(CONTEXT).getContext(); + assertThat(context.getBeansOfType(AuthenticationEventPublisher.class)).hasSize(1); + } + + @Test + public void onlyOneEventPublisherIsRegisteredForMultipleAuthenticationManagers() { + ConfigurableApplicationContext context = this.spring.context(CONTEXT + '\n' + CONTEXT_MULTI).getContext(); + assertThat(context.getBeansOfType(AuthenticationEventPublisher.class)).hasSize(1); + } + @Test public void eventsArePublishedByDefault() throws Exception { ConfigurableApplicationContext appContext = this.spring.context(CONTEXT).getContext();