Merge branch '1.1.x'

This commit is contained in:
Dave Syer 2014-09-13 06:44:03 -05:00
commit 389c4f3e0b
4 changed files with 117 additions and 65 deletions

View File

@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -41,9 +42,15 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.stereotype.Component;
/**
* Configuration for a Spring Security in-memory {@link AuthenticationManager}.
* Configuration for a Spring Security in-memory {@link AuthenticationManager}. Can be
* disabled by providing a bean of type AuthenticationManager. The value provided by this
* configuration will become the "global" authentication manager (from Spring Security),
* or the parent of the global instance. Thus it acts as a fallback when no others are
* provided, is used by method security if enabled, and as a parent authentication manager
* for "local" authentication managers in individual filter chains.
*
* @author Dave Syer
* @author Rob Winch
@ -53,8 +60,15 @@ import org.springframework.security.config.annotation.authentication.configurers
@ConditionalOnMissingBean(AuthenticationManager.class)
@Order(Ordered.LOWEST_PRECEDENCE - 3)
public class AuthenticationManagerConfiguration extends
GlobalAuthenticationConfigurerAdapter implements
ApplicationListener<ContextRefreshedEvent> {
GlobalAuthenticationConfigurerAdapter {
/*
* Yes, this class is a GlobalAuthenticationConfigurerAdapter, even though none of
* those methods are overridden: we want Spring Security to instantiate us early, so
* we can in turn force the SecurityPrequisites to be instantiated. This will prevent
* ordering issues between Spring Boot modules when they need to influence the default
* security configuration.
*/
private static Log logger = LogFactory
.getLog(AuthenticationManagerConfiguration.class);
@ -62,43 +76,48 @@ public class AuthenticationManagerConfiguration extends
@Autowired
private List<SecurityPrequisite> dependencies;
@Autowired
private ObjectPostProcessor<Object> objectPostProcessor;
@Autowired
private SecurityProperties security;
@Autowired
private AuthenticationEventPublisher authenticationEventPublisher;
private BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(this.configurer);
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
this.configurer.configureParent(auth);
}
private ObjectPostProcessor<Object> objectPostProcessor;
@Bean
@Primary
public AuthenticationManager authenticationManager() {
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth)
throws Exception {
/*
* This AuthenticationManagerBuilder is for the global AuthenticationManager
*/
BootDefaultingAuthenticationConfigurerAdapter configurer = new BootDefaultingAuthenticationConfigurerAdapter();
configurer.init(auth);
configurer.configure(auth);
AuthenticationManager manager = configurer.getAuthenticationManagerBuilder()
.getOrBuild();
configurer.configureParent(auth);
return manager;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
AuthenticationManager manager = this.configurer.getAuthenticationManagerBuilder()
.getOrBuild();
if (manager instanceof ProviderManager) {
((ProviderManager) manager)
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
@Component
protected static class AuthenticationManagerConfigurationListener implements
ApplicationListener<ContextRefreshedEvent> {
@Autowired
private AuthenticationEventPublisher authenticationEventPublisher;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext context = event.getApplicationContext();
if (context.getBeanNamesForType(AuthenticationManager.class).length == 0) {
return;
}
AuthenticationManager manager = context.getBean(AuthenticationManager.class);
if (manager instanceof ProviderManager) {
((ProviderManager) manager)
.setAuthenticationEventPublisher(this.authenticationEventPublisher);
}
}
}
/**
@ -163,7 +182,8 @@ public class AuthenticationManagerConfiguration extends
.roles(roles.toArray(new String[roles.size()])).and().and().build();
// Defer actually setting the parent on the AuthenticationManagerBuilder
// because it makes it "configured" and we are only in the init() phase here.
// because it makes it "configured" and we are only in the init() phase
// here.
}
}

View File

@ -18,15 +18,29 @@ package org.springframework.boot.autoconfigure.web;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.web.BasicErrorControllerMockMvcTests.MinimalWebConfiguration;
import org.springframework.boot.autoconfigure.web.BasicErrorControllerMockMvcTests.TestConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.AbstractView;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
@ -40,8 +54,9 @@ import static org.junit.Assert.assertThat;
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = BasicErrorControllerMockMvcTests.TestConfiguration.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
@WebAppConfiguration
@DirtiesContext
@IntegrationTest("server.port=0")
public class BasicErrorControllerIntegrationTest {
@ -69,4 +84,49 @@ public class BasicErrorControllerIntegrationTest {
assertThat(resp, containsString("errors=[{codes="));
assertThat(resp, containsString("org.springframework.validation.BindException"));
}
@Configuration
@MinimalWebConfiguration
public static class TestConfiguration {
// For manual testing
public static void main(String[] args) {
SpringApplication.run(TestConfiguration.class, args);
}
@Bean
public View error() {
return new AbstractView() {
@Override
protected void renderMergedOutputModel(Map<String, Object> model,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.getWriter().write("ERROR_BEAN");
}
};
}
@RestController
protected static class Errors {
public String getFoo() {
return "foo";
}
@RequestMapping("/")
public String home() {
throw new IllegalStateException("Expected!");
}
@RequestMapping("/bind")
public String bind() throws Exception {
BindException error = new BindException(this, "test");
error.rejectValue("foo", "bar.error");
throw error;
}
}
}
}

View File

@ -23,18 +23,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>

View File

@ -19,18 +19,14 @@ package sample.ui.secure;
import java.util.Date;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.Ordered;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.stereotype.Controller;
@ -65,16 +61,7 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter {
registry.addViewController("/login").setViewName("login");
}
@Bean
public ApplicationSecurity applicationSecurity() {
return new ApplicationSecurity();
}
@Bean
public AuthenticationSecurity authenticationSecurity() {
return new AuthenticationSecurity();
}
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@ -86,21 +73,14 @@ public class SampleWebSecureApplication extends WebMvcConfigurerAdapter {
http.authorizeRequests().anyRequest().fullyAuthenticated().and().formLogin()
.loginPage("/login").failureUrl("/login?error").permitAll();
}
}
@Order(Ordered.HIGHEST_PRECEDENCE + 10)
protected static class AuthenticationSecurity extends
GlobalAuthenticationConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource).withUser("admin")
.password("admin").roles("ADMIN", "USER").and().withUser("user")
.password("user").roles("USER");
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin")
.roles("ADMIN", "USER").and().withUser("user").password("user")
.roles("USER");
}
}
}