Commit 38f8d657 authored by Dave Syer's avatar Dave Syer

Use ApplicationEvent to ensure that authentication event publisher is registered

There was a reference to an old (fixed) issue in Spring which led to some simplification
of the AuthenticationManager layering as well.

Fixes gh-1335
parent 88828f50
...@@ -26,12 +26,14 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -26,12 +26,14 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties.User; import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
import org.springframework.context.ApplicationListener;
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.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationEventPublisher; import org.springframework.security.authentication.AuthenticationEventPublisher;
...@@ -54,7 +56,8 @@ import org.springframework.security.config.annotation.authentication.configurers ...@@ -54,7 +56,8 @@ import org.springframework.security.config.annotation.authentication.configurers
@ConditionalOnMissingBean(AuthenticationManager.class) @ConditionalOnMissingBean(AuthenticationManager.class)
@Order(Ordered.LOWEST_PRECEDENCE - 3) @Order(Ordered.LOWEST_PRECEDENCE - 3)
public class AuthenticationManagerConfiguration extends public class AuthenticationManagerConfiguration extends
GlobalAuthenticationConfigurerAdapter { GlobalAuthenticationConfigurerAdapter implements
ApplicationListener<ContextRefreshedEvent> {
private static Log logger = LogFactory private static Log logger = LogFactory
.getLog(AuthenticationManagerConfiguration.class); .getLog(AuthenticationManagerConfiguration.class);
...@@ -79,23 +82,23 @@ public class AuthenticationManagerConfiguration extends ...@@ -79,23 +82,23 @@ public class AuthenticationManagerConfiguration extends
} }
@Bean @Bean
// avoid issues with scopedTarget (SPR-11548)
@Primary @Primary
@Lazy
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
public AuthenticationManager authenticationManager() { public AuthenticationManager authenticationManager() {
return lazyAuthenticationManager(); AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
.getOrBuild();
return manager;
} }
@Bean @Override
@Lazy public void onApplicationEvent(ContextRefreshedEvent event) {
@Scope(proxyMode = ScopedProxyMode.INTERFACES)
protected AuthenticationManager lazyAuthenticationManager() {
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder() AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
.getOrBuild(); .getOrBuild();
if (manager instanceof ProviderManager) { if (manager instanceof ProviderManager) {
((ProviderManager) manager) ((ProviderManager) manager)
.setAuthenticationEventPublisher(this.authenticationEventPublisher); .setAuthenticationEventPublisher(this.authenticationEventPublisher);
} }
return manager;
} }
/** /**
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure.security; package org.springframework.boot.autoconfigure.security;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
...@@ -26,12 +27,17 @@ import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurat ...@@ -26,12 +27,17 @@ import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfigurat
import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration; import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
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.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
...@@ -41,6 +47,8 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon ...@@ -41,6 +47,8 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/** /**
* Tests for {@link SecurityAutoConfiguration}. * Tests for {@link SecurityAutoConfiguration}.
...@@ -104,6 +112,27 @@ public class SecurityAutoConfigurationTests { ...@@ -104,6 +112,27 @@ public class SecurityAutoConfigurationTests {
assertNotNull(this.context.getBean(AuthenticationManager.class)); assertNotNull(this.context.getBean(AuthenticationManager.class));
} }
@Test
public void testEventPublisherInjected() throws Exception {
testAuthenticationManagerCreated();
final AtomicReference<ApplicationEvent> wrapper = new AtomicReference<ApplicationEvent>();
this.context.addApplicationListener(new ApplicationListener<ApplicationEvent>() {
@Override
public void onApplicationEvent(ApplicationEvent event) {
wrapper.set(event);
};
});
AuthenticationManager manager = this.context.getBean(AuthenticationManager.class);
try {
manager.authenticate(new UsernamePasswordAuthenticationToken("foo", "bar"));
fail("Expected BadCredentialsException");
}
catch (BadCredentialsException e) {
// expected
}
assertTrue(wrapper.get() instanceof AuthenticationFailureBadCredentialsEvent);
}
@Test @Test
public void testOverrideAuthenticationManager() throws Exception { public void testOverrideAuthenticationManager() throws Exception {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
......
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<!-- Your own application should inherit from spring-boot-starter-parent --> <!-- Your own application should inherit from spring-boot-starter-parent -->
...@@ -16,6 +17,7 @@ ...@@ -16,6 +17,7 @@
<url>http://www.spring.io</url> <url>http://www.spring.io</url>
</organization> </organization>
<properties> <properties>
<start-class>sample.parent.SampleParentContextApplication</start-class>
<main.basedir>${basedir}/../..</main.basedir> <main.basedir>${basedir}/../..</main.basedir>
</properties> </properties>
<dependencies> <dependencies>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment