瀏覽代碼

Improve AuthenticationManagerBeanDefinitionParser XML parsing

Closes gh-7282
/usr/local/ΕΨΗΕΛΩΝ 4 年之前
父節點
當前提交
50a17f58db

+ 12 - 6
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);

+ 25 - 1
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 {
 			+ "</authentication-manager>";
 	// @formatter:on
 
+	// Issue #7282
+	// @formatter:off
+	private static final String CONTEXT_MULTI = "<authentication-manager id='amSecondary'>"
+			+ "    <authentication-provider>"
+			+ "        <user-service>"
+			+ "            <user name='john' password='{noop}doe' authorities='ROLE_C,ROLE_D' />"
+			+ "        </user-service>"
+			+ "    </authentication-provider>"
+			+ "</authentication-manager>";
+	// @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();