Commit bd26b28a authored by Dave Syer's avatar Dave Syer

Extract actuator security into separate classes

So spring-security + a web app is secure by default
(you don't need the actuator).
parent 285dd5b2
...@@ -44,8 +44,7 @@ import org.crsh.vfs.spi.AbstractFSDriver; ...@@ -44,8 +44,7 @@ import org.crsh.vfs.spi.AbstractFSDriver;
import org.crsh.vfs.spi.FSDriver; import org.crsh.vfs.spi.FSDriver;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.properties.SecurityProperties; import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.actuate.properties.SecurityProperties.Management;
import org.springframework.boot.actuate.properties.ShellProperties; import org.springframework.boot.actuate.properties.ShellProperties;
import org.springframework.boot.actuate.properties.ShellProperties.CrshShellAuthenticationProperties; import org.springframework.boot.actuate.properties.ShellProperties.CrshShellAuthenticationProperties;
import org.springframework.boot.actuate.properties.ShellProperties.CrshShellProperties; import org.springframework.boot.actuate.properties.ShellProperties.CrshShellProperties;
...@@ -96,8 +95,9 @@ import org.springframework.util.StringUtils; ...@@ -96,8 +95,9 @@ import org.springframework.util.StringUtils;
* Security. This authentication method will get enabled if <code>shell.auth</code> is set * Security. This authentication method will get enabled if <code>shell.auth</code> is set
* to <code>spring</code> or if no explicit <code>shell.auth</code> is provided and a * to <code>spring</code> or if no explicit <code>shell.auth</code> is provided and a
* {@link AuthenticationManager} is available. In the latter case shell access will be * {@link AuthenticationManager} is available. In the latter case shell access will be
* restricted to users having roles that match those configured in {@link Management}. * restricted to users having roles that match those configured in
* Required roles can be overridden by <code>shell.auth.spring.roles</code>. * {@link ManagementServerProperties}. Required roles can be overridden by
* <code>shell.auth.spring.roles</code>.
* *
* <p> * <p>
* To add customizations to the shell simply define beans of type {@link CRaSHPlugin} in * To add customizations to the shell simply define beans of type {@link CRaSHPlugin} in
...@@ -119,7 +119,7 @@ import org.springframework.util.StringUtils; ...@@ -119,7 +119,7 @@ import org.springframework.util.StringUtils;
@Configuration @Configuration
@ConditionalOnClass({ PluginLifeCycle.class }) @ConditionalOnClass({ PluginLifeCycle.class })
@EnableConfigurationProperties({ ShellProperties.class }) @EnableConfigurationProperties({ ShellProperties.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class) @AutoConfigureAfter(ManagementSecurityAutoConfiguration.class)
public class CrshAutoConfiguration { public class CrshAutoConfiguration {
@Autowired @Autowired
...@@ -170,7 +170,7 @@ public class CrshAutoConfiguration { ...@@ -170,7 +170,7 @@ public class CrshAutoConfiguration {
public static class AuthenticationManagerAdapterAutoConfiguration { public static class AuthenticationManagerAdapterAutoConfiguration {
@Autowired(required = false) @Autowired(required = false)
private SecurityProperties securityProperties; private ManagementServerProperties management;
@Bean @Bean
public CRaSHPlugin<?> shellAuthenticationManager() { public CRaSHPlugin<?> shellAuthenticationManager() {
...@@ -184,9 +184,9 @@ public class CrshAutoConfiguration { ...@@ -184,9 +184,9 @@ public class CrshAutoConfiguration {
// In case no shell.auth property is provided fall back to Spring Security // In case no shell.auth property is provided fall back to Spring Security
// based authentication and get role to access shell from SecurityProperties. // based authentication and get role to access shell from SecurityProperties.
SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties(); SpringAuthenticationProperties authenticationProperties = new SpringAuthenticationProperties();
if (this.securityProperties != null) { if (this.management != null) {
authenticationProperties.setRoles(new String[] { this.securityProperties authenticationProperties.setRoles(new String[] { this.management
.getManagement().getRole() }); .getSecurity().getRole() });
} }
return authenticationProperties; return authenticationProperties;
} }
......
...@@ -52,7 +52,6 @@ import org.springframework.context.annotation.Configuration; ...@@ -52,7 +52,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
...@@ -182,7 +181,7 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware, ...@@ -182,7 +181,7 @@ public class EndpointWebMvcAutoConfiguration implements ApplicationContextAware,
if (DISABLED_PORT.equals(managementServerProperties.getPort())) { if (DISABLED_PORT.equals(managementServerProperties.getPort())) {
return DISABLE; return DISABLE;
} }
if (!(beanFactory instanceof GenericWebApplicationContext)) { if (!(beanFactory instanceof WebApplicationContext)) {
// Current context is no a a webapp // Current context is no a a webapp
return DIFFERENT; return DIFFERENT;
} }
......
/*
* Copyright 2012-2013 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
*
* http://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.boot.actuate.autoconfigure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
import org.springframework.boot.actuate.properties.ManagementServerProperties;
import org.springframework.boot.actuate.web.ErrorController;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.AuthenticationManagerConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityPrequisite;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity.IgnoredRequestConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
/**
* {@link EnableAutoConfiguration Auto-configuration} for security of framework endpoints.
* Many aspects of the behavior can be controller with {@link ManagementServerProperties}
* via externalized application properties (or via an bean definition of that type to set
* the defaults).
*
* <p>
* The framework {@link Endpoint}s (used to expose application information to operations)
* include a {@link Endpoint#isSensitive() sensitive} configuration option which will be
* used as a security hint by the filter created here.
*
* @author Dave Syer
*/
@Configuration
@ConditionalOnClass({ EnableWebSecurity.class })
@AutoConfigureAfter(SecurityAutoConfiguration.class)
@EnableConfigurationProperties
public class ManagementSecurityAutoConfiguration {
private static final String[] NO_PATHS = new String[0];
@Bean
@ConditionalOnMissingBean({ IgnoredPathsWebSecurityConfigurerAdapter.class })
public SecurityConfigurer<Filter, WebSecurity> ignoredPathsWebSecurityConfigurerAdapter() {
return new IgnoredPathsWebSecurityConfigurerAdapter();
}
@Configuration
protected static class ManagementSecurityPropertiesConfiguration implements
SecurityPrequisite {
@Autowired(required = false)
private SecurityProperties security;
@Autowired(required = false)
private ManagementServerProperties management;
@PostConstruct
public void init() {
if (this.management != null && this.security != null) {
this.security.getUser().getRole()
.add(this.management.getSecurity().getRole());
}
}
}
// Get the ignored paths in early
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
private static class IgnoredPathsWebSecurityConfigurerAdapter implements
SecurityConfigurer<Filter, WebSecurity> {
@Autowired(required = false)
private ErrorController errorController;
@Autowired(required = false)
private EndpointHandlerMapping endpointHandlerMapping;
@Autowired
private ManagementServerProperties management;
@Autowired
private SecurityProperties security;
@Override
public void configure(WebSecurity builder) throws Exception {
}
@Override
public void init(WebSecurity builder) throws Exception {
IgnoredRequestConfigurer ignoring = builder.ignoring();
// The ignores are not cumulative, so to prevent overwriting the defaults we
// add them back.
List<String> ignored = SecurityAutoConfiguration.getIgnored(this.security);
ignored.addAll(Arrays.asList(getEndpointPaths(this.endpointHandlerMapping,
false)));
if (!this.management.getSecurity().isEnabled()) {
ignored.addAll(Arrays.asList(getEndpointPaths(
this.endpointHandlerMapping, true)));
}
if (ignored.contains("none")) {
ignored.remove("none");
}
if (this.errorController != null) {
ignored.add(this.errorController.getErrorPath());
}
ignoring.antMatchers(ignored.toArray(new String[0]));
}
}
@Configuration
@ConditionalOnMissingBean({ ManagementWebSecurityConfigurerAdapter.class })
@ConditionalOnExpression("${management.security.enabled:true}")
@EnableWebSecurity
// Give user-supplied filters a chance to be last in line
@Order(Ordered.LOWEST_PRECEDENCE - 10)
protected static class ManagementWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
@Autowired
private SecurityProperties security;
@Autowired
private ManagementServerProperties management;
@Autowired(required = false)
private EndpointHandlerMapping endpointHandlerMapping;
@Override
protected void configure(HttpSecurity http) throws Exception {
// secure endpoints
String[] paths = getEndpointPaths(this.endpointHandlerMapping, true);
if (paths.length > 0 && this.management.getSecurity().isEnabled()) {
// Always protect them if present
if (this.security.isRequireSsl()) {
http.requiresChannel().anyRequest().requiresSecure();
}
http.exceptionHandling().authenticationEntryPoint(entryPoint());
http.requestMatchers().antMatchers(paths);
http.authorizeRequests().anyRequest()
.hasRole(this.management.getSecurity().getRole()) //
.and().httpBasic() //
.and().anonymous().disable();
// No cookies for management endpoints by default
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(
this.management.getSecurity().getSessions());
SecurityAutoConfiguration.configureHeaders(http.headers(),
this.security.getHeaders());
}
}
private AuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
entryPoint.setRealmName(this.security.getBasic().getRealm());
return entryPoint;
}
@Configuration
@ConditionalOnMissingBean(AuthenticationManager.class)
protected static class ManagementAuthenticationManagerConfiguration extends
AuthenticationManagerConfiguration {
}
}
private static String[] getEndpointPaths(
EndpointHandlerMapping endpointHandlerMapping, boolean secure) {
if (endpointHandlerMapping == null) {
return NO_PATHS;
}
List<Endpoint<?>> endpoints = endpointHandlerMapping.getEndpoints();
List<String> paths = new ArrayList<String>(endpoints.size());
for (Endpoint<?> endpoint : endpoints) {
if (endpoint.isSensitive() == secure) {
paths.add(endpoint.getPath());
}
}
return paths.toArray(new String[paths.size()]);
}
}
...@@ -38,7 +38,7 @@ public class ManagementServerPropertiesAutoConfiguration { ...@@ -38,7 +38,7 @@ public class ManagementServerPropertiesAutoConfiguration {
@Bean(name = "org.springframework.actuate.properties.ManagementServerProperties") @Bean(name = "org.springframework.actuate.properties.ManagementServerProperties")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ManagementServerProperties serverProperties() { public ManagementServerProperties managementServerProperties() {
return new ManagementServerProperties(); return new ManagementServerProperties();
} }
......
...@@ -20,8 +20,11 @@ import java.net.InetAddress; ...@@ -20,8 +20,11 @@ import java.net.InetAddress;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import org.springframework.boot.autoconfigure.security.SecurityPrequisite;
import org.springframework.boot.context.embedded.properties.ServerProperties; import org.springframework.boot.context.embedded.properties.ServerProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.util.ClassUtils;
/** /**
* Properties for the management server (e.g. port and path settings). * Properties for the management server (e.g. port and path settings).
...@@ -30,7 +33,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; ...@@ -30,7 +33,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @see ServerProperties * @see ServerProperties
*/ */
@ConfigurationProperties(name = "management", ignoreUnknownFields = false) @ConfigurationProperties(name = "management", ignoreUnknownFields = false)
public class ManagementServerProperties { public class ManagementServerProperties implements SecurityPrequisite {
private Integer port; private Integer port;
...@@ -41,6 +44,8 @@ public class ManagementServerProperties { ...@@ -41,6 +44,8 @@ public class ManagementServerProperties {
private boolean allowShutdown = false; private boolean allowShutdown = false;
private Security security = maybeCreateSecurity();
public boolean isAllowShutdown() { public boolean isAllowShutdown() {
return this.allowShutdown; return this.allowShutdown;
} }
...@@ -82,4 +87,50 @@ public class ManagementServerProperties { ...@@ -82,4 +87,50 @@ public class ManagementServerProperties {
this.contextPath = contextPath; this.contextPath = contextPath;
} }
public Security getSecurity() {
return this.security;
}
public static class Security {
private boolean enabled = true;
private String role = "ADMIN";
private SessionCreationPolicy sessions = SessionCreationPolicy.STATELESS;
public SessionCreationPolicy getSessions() {
return this.sessions;
}
public void setSessions(SessionCreationPolicy sessions) {
this.sessions = sessions;
}
public void setRole(String role) {
this.role = role;
}
public String getRole() {
return this.role;
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
private static Security maybeCreateSecurity() {
if (ClassUtils
.isPresent("org.springframework.security.core.Authentication", null)) {
return new Security();
}
return null;
}
} }
...@@ -7,6 +7,6 @@ org.springframework.boot.actuate.autoconfigure.ErrorMvcAutoConfiguration,\ ...@@ -7,6 +7,6 @@ org.springframework.boot.actuate.autoconfigure.ErrorMvcAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementServerPropertiesAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.MetricRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.SecurityAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,\ org.springframework.boot.actuate.autoconfigure.TraceRepositoryAutoConfiguration,\
org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration org.springframework.boot.actuate.autoconfigure.TraceWebFilterAutoConfiguration
...@@ -33,6 +33,7 @@ import org.crsh.processor.term.ProcessorIOHandler; ...@@ -33,6 +33,7 @@ import org.crsh.processor.term.ProcessorIOHandler;
import org.crsh.vfs.Resource; import org.crsh.vfs.Resource;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
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.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
......
/*
* Copyright 2012-2013 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
*
* http://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.boot.actuate.autoconfigure;
import org.junit.Test;
import org.springframework.boot.TestUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInitializer;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link ManagementSecurityAutoConfiguration}.
*
* @author Dave Syer
*/
public class ManagementSecurityAutoConfigurationTests {
private AnnotationConfigWebApplicationContext context;
@Test
public void testWebConfiguration() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertNotNull(this.context.getBean(AuthenticationManager.class));
// 6 for static resources, one for management endpoints and one for the rest
assertEquals(8, this.context.getBean(FilterChainProxy.class).getFilterChains()
.size());
}
@Test
public void testWebConfigurationWithExtraRole() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(EndpointAutoConfiguration.class,
EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
debugRefresh(this.context);
UserDetails user = getUser();
assertTrue(user.getAuthorities().containsAll(
AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_USER,ROLE_ADMIN")));
}
private UserDetails getUser() {
ProviderManager manager = this.context.getBean(ProviderManager.class);
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) manager
.getProviders().get(0);
UserDetailsService service = (UserDetailsService) ReflectionTestUtils.getField(
provider, "userDetailsService");
UserDetails user = service.loadUserByUsername("user");
return user;
}
@Test
public void testDisableIgnoredStaticApplicationPaths() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "security.ignored:none");
this.context.refresh();
// Just the application and management endpoints now
assertEquals(2, this.context.getBean(FilterChainProxy.class).getFilterChains()
.size());
}
@Test
public void testDisableBasicAuthOnApplicationPaths() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class,
ManagementSecurityAutoConfiguration.class,
EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "security.basic.enabled:false");
this.context.refresh();
// Just the management endpoints (one filter) and ignores now
assertEquals(7, this.context.getBean(FilterChainProxy.class).getFilterChains()
.size());
}
@Test
public void testOverrideAuthenticationManager() throws Exception {
this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext());
this.context.register(TestConfiguration.class,
SecurityAutoConfiguration.class, ManagementSecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
assertEquals(this.context.getBean(TestConfiguration.class).authenticationManager,
this.context.getBean(AuthenticationManager.class));
}
private static AnnotationConfigWebApplicationContext debugRefresh(
AnnotationConfigWebApplicationContext context) {
TestUtils.addEnviroment(context, "debug:true");
LoggingApplicationContextInitializer logging = new LoggingApplicationContextInitializer();
logging.initialize(context);
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
initializer.initialize(context);
context.refresh();
initializer.onApplicationEvent(new ContextRefreshedEvent(context));
return context;
}
@Configuration
protected static class TestConfiguration {
private AuthenticationManager authenticationManager;
@Bean
public AuthenticationManager myAuthenticationManager() {
this.authenticationManager = new AuthenticationManager() {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
return new TestingAuthenticationToken("foo", "bar");
}
};
return this.authenticationManager;
}
}
}
...@@ -126,6 +126,16 @@ ...@@ -126,6 +126,16 @@
<artifactId>spring-security-acl</artifactId> <artifactId>spring-security-acl</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.amqp</groupId> <groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId> <artifactId>spring-rabbit</artifactId>
......
/*
* Copyright 2012-2013 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
*
* http://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.boot.autoconfigure.security;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer;
@Configuration
public class AuthenticationManagerConfiguration {
private static Log logger = LogFactory
.getLog(AuthenticationManagerConfiguration.class);
@Autowired
private SecurityProperties security;
@Autowired
private List<SecurityPrequisite> dependencies;
@Bean
public AuthenticationManager authenticationManager(
ObjectPostProcessor<Object> objectPostProcessor) throws Exception {
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> builder = new AuthenticationManagerBuilder(
objectPostProcessor).inMemoryAuthentication();
User user = this.security.getUser();
if (user.isDefaultPassword()) {
logger.info("\n\nUsing default password for application endpoints: "
+ user.getPassword() + "\n\n");
}
// TODO: Add the management role...
Set<String> roles = new LinkedHashSet<String>(user.getRole());
builder.withUser(user.getName()).password(user.getPassword())
.roles(roles.toArray(new String[roles.size()]));
return builder.and().build();
}
}
\ No newline at end of file
/*
* Copyright 2012-2013 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
*
* http://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.boot.autoconfigure.security;
/**
* Marker interface for beans that need to be initialized before any security
* configuration is evaluated.
*
* @author Dave Syer
*/
public interface SecurityPrequisite {
}
...@@ -14,9 +14,10 @@ ...@@ -14,9 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.properties; package org.springframework.boot.autoconfigure.security;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
...@@ -30,7 +31,7 @@ import org.springframework.util.StringUtils; ...@@ -30,7 +31,7 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
*/ */
@ConfigurationProperties(name = "security", ignoreUnknownFields = false) @ConfigurationProperties(name = "security", ignoreUnknownFields = false)
public class SecurityProperties { public class SecurityProperties implements SecurityPrequisite {
private boolean requireSsl; private boolean requireSsl;
...@@ -45,8 +46,6 @@ public class SecurityProperties { ...@@ -45,8 +46,6 @@ public class SecurityProperties {
private List<String> ignored = new ArrayList<String>(); private List<String> ignored = new ArrayList<String>();
private Management management = new Management();
private User user = new User(); private User user = new User();
public Headers getHeaders() { public Headers getHeaders() {
...@@ -57,10 +56,6 @@ public class SecurityProperties { ...@@ -57,10 +56,6 @@ public class SecurityProperties {
return this.user; return this.user;
} }
public Management getManagement() {
return this.management;
}
public SessionCreationPolicy getSessions() { public SessionCreationPolicy getSessions() {
return this.sessions; return this.sessions;
} }
...@@ -193,47 +188,13 @@ public class SecurityProperties { ...@@ -193,47 +188,13 @@ public class SecurityProperties {
} }
public static class Management {
private boolean enabled = true;
private String role = "ADMIN";
private SessionCreationPolicy sessions = SessionCreationPolicy.STATELESS;
public SessionCreationPolicy getSessions() {
return this.sessions;
}
public void setSessions(SessionCreationPolicy sessions) {
this.sessions = sessions;
}
public void setRole(String role) {
this.role = role;
}
public String getRole() {
return this.role;
}
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public static class User { public static class User {
private String name = "user"; private String name = "user";
private String password = UUID.randomUUID().toString(); private String password = UUID.randomUUID().toString();
private String role = "USER"; private List<String> role = new ArrayList<String>(Arrays.asList("USER"));
private boolean defaultPassword = true; private boolean defaultPassword = true;
...@@ -258,14 +219,10 @@ public class SecurityProperties { ...@@ -258,14 +219,10 @@ public class SecurityProperties {
this.password = password; this.password = password;
} }
public String getRole() { public List<String> getRole() {
return this.role; return this.role;
} }
public void setRole(String role) {
this.role = role;
}
public boolean isDefaultPassword() { public boolean isDefaultPassword() {
return this.defaultPassword; return this.defaultPassword;
} }
......
...@@ -14,6 +14,7 @@ org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\ ...@@ -14,6 +14,7 @@ org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\ org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\ org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
......
...@@ -14,13 +14,16 @@ ...@@ -14,13 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.autoconfigure; package org.springframework.boot.autoconfigure.security;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.TestUtils; import org.springframework.boot.TestUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInitializer;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.initializer.LoggingApplicationContextInitializer;
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.event.ContextRefreshedEvent;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.TestingAuthenticationToken;
...@@ -46,13 +49,11 @@ public class SecurityAutoConfigurationTests { ...@@ -46,13 +49,11 @@ public class SecurityAutoConfigurationTests {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext()); this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class, this.context.register(SecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); debugRefresh(this.context);
assertNotNull(this.context.getBean(AuthenticationManager.class)); assertNotNull(this.context.getBean(AuthenticationManager.class));
// 4 for static resources, one for management endpoints and one for the rest // 4 for static resources and one for the rest
assertEquals(6, this.context.getBean(FilterChainProxy.class).getFilterChains() assertEquals(5, this.context.getBean(FilterChainProxy.class).getFilterChains()
.size()); .size());
} }
...@@ -61,13 +62,11 @@ public class SecurityAutoConfigurationTests { ...@@ -61,13 +62,11 @@ public class SecurityAutoConfigurationTests {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext()); this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class, this.context.register(SecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "security.ignored:none"); TestUtils.addEnviroment(this.context, "security.ignored:none");
this.context.refresh(); this.context.refresh();
// Just the application and management endpoints now // Just the application endpoints now
assertEquals(2, this.context.getBean(FilterChainProxy.class).getFilterChains() assertEquals(1, this.context.getBean(FilterChainProxy.class).getFilterChains()
.size()); .size());
} }
...@@ -76,14 +75,11 @@ public class SecurityAutoConfigurationTests { ...@@ -76,14 +75,11 @@ public class SecurityAutoConfigurationTests {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext()); this.context.setServletContext(new MockServletContext());
this.context.register(SecurityAutoConfiguration.class, this.context.register(SecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
TestUtils.addEnviroment(this.context, "security.basic.enabled:false"); TestUtils.addEnviroment(this.context, "security.basic.enabled:false");
this.context.refresh(); this.context.refresh();
// Just the management endpoints and default ignores now // No security at all not even ignores
assertEquals(5, this.context.getBean(FilterChainProxy.class).getFilterChains() assertEquals(0, this.context.getBeanNamesForType(FilterChainProxy.class).length);
.size());
} }
@Test @Test
...@@ -91,14 +87,24 @@ public class SecurityAutoConfigurationTests { ...@@ -91,14 +87,24 @@ public class SecurityAutoConfigurationTests {
this.context = new AnnotationConfigWebApplicationContext(); this.context = new AnnotationConfigWebApplicationContext();
this.context.setServletContext(new MockServletContext()); this.context.setServletContext(new MockServletContext());
this.context.register(TestConfiguration.class, SecurityAutoConfiguration.class, this.context.register(TestConfiguration.class, SecurityAutoConfiguration.class,
EndpointAutoConfiguration.class,
ManagementServerPropertiesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
assertEquals(this.context.getBean(TestConfiguration.class).authenticationManager, assertEquals(this.context.getBean(TestConfiguration.class).authenticationManager,
this.context.getBean(AuthenticationManager.class)); this.context.getBean(AuthenticationManager.class));
} }
private static AnnotationConfigWebApplicationContext debugRefresh(
AnnotationConfigWebApplicationContext context) {
TestUtils.addEnviroment(context, "debug:true");
LoggingApplicationContextInitializer logging = new LoggingApplicationContextInitializer();
logging.initialize(context);
AutoConfigurationReportLoggingInitializer initializer = new AutoConfigurationReportLoggingInitializer();
initializer.initialize(context);
context.refresh();
initializer.onApplicationEvent(new ContextRefreshedEvent(context));
return context;
}
@Configuration @Configuration
protected static class TestConfiguration { protected static class TestConfiguration {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.actuate.properties; package org.springframework.boot.autoconfigure.security;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
...@@ -22,6 +22,7 @@ import java.util.Map; ...@@ -22,6 +22,7 @@ import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.bind.RelaxedDataBinder; import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
......
...@@ -44,8 +44,7 @@ public class ReproIntegrationTests { ...@@ -44,8 +44,7 @@ public class ReproIntegrationTests {
@Test @Test
public void securityDependencies() throws Exception { public void securityDependencies() throws Exception {
this.cli.run("secure.groovy"); this.cli.run("secure.groovy");
assertThat(this.cli.getHttpOutput(), assertThat(this.cli.getOutput(), containsString("Hello World"));
containsString("{\"message\":\"Hello World\"}"));
} }
@Test @Test
......
...@@ -3,12 +3,12 @@ package org.test ...@@ -3,12 +3,12 @@ package org.test
// No security features added just a test that the dependencies are resolved // No security features added just a test that the dependencies are resolved
@Grab("spring-boot-starter-security") @Grab("spring-boot-starter-security")
@RestController @Controller
class SampleController { class Sample implements CommandLineRunner {
@RequestMapping("/") @Override
public def hello() { void run(String... args) {
[message: "Hello World"] println "Hello World"
} }
} }
......
...@@ -20,8 +20,8 @@ import java.util.Date; ...@@ -20,8 +20,8 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.properties.SecurityProperties;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
......
...@@ -30,7 +30,7 @@ import org.junit.BeforeClass; ...@@ -30,7 +30,7 @@ import org.junit.BeforeClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.properties.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
......
...@@ -29,7 +29,7 @@ import org.junit.AfterClass; ...@@ -29,7 +29,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.properties.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
......
...@@ -35,7 +35,7 @@ import org.junit.AfterClass; ...@@ -35,7 +35,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.properties.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
......
...@@ -29,7 +29,7 @@ import org.junit.AfterClass; ...@@ -29,7 +29,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.properties.SecurityProperties; import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
......
...@@ -57,7 +57,7 @@ public class UnsecureManagementSampleActuatorApplicationTests { ...@@ -57,7 +57,7 @@ public class UnsecureManagementSampleActuatorApplicationTests {
public ConfigurableApplicationContext call() throws Exception { public ConfigurableApplicationContext call() throws Exception {
return SpringApplication.run( return SpringApplication.run(
SampleActuatorApplication.class, SampleActuatorApplication.class,
"--security.management.enabled=false"); "--management.security.enabled=false");
} }
}); });
context = future.get(60, TimeUnit.SECONDS); context = future.get(60, TimeUnit.SECONDS);
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-security</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
...@@ -24,14 +24,6 @@ ...@@ -24,14 +24,6 @@
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.thymeleaf</groupId> <groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId> <artifactId>thymeleaf-spring3</artifactId>
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
package org.springframework.boot.sample.ops.ui; package org.springframework.boot.sample.ops.ui;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
...@@ -39,9 +41,6 @@ import org.springframework.http.client.ClientHttpResponse; ...@@ -39,9 +41,6 @@ import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.DefaultResponseErrorHandler; import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/** /**
* Basic integration tests for demo application. * Basic integration tests for demo application.
* *
...@@ -92,30 +91,6 @@ public class SampleSecureApplicationTests { ...@@ -92,30 +91,6 @@ public class SampleSecureApplicationTests {
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody().contains("body")); assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody().contains("body"));
} }
@Test
public void testMetrics() throws Exception {
@SuppressWarnings("rawtypes")
ResponseEntity<Map> entity = getRestTemplate().getForEntity(
"http://localhost:8080/metrics", Map.class);
assertEquals(HttpStatus.UNAUTHORIZED, entity.getStatusCode());
}
@Test
public void testError() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
ResponseEntity<String> entity = getRestTemplate().exchange(
"http://localhost:8080/error", HttpMethod.GET,
new HttpEntity<Void>(headers), String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody()
.contains("<html>"));
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody()
.contains("<body>"));
assertTrue("Wrong body:\n" + entity.getBody(), entity.getBody()
.contains("Please contact the operator with the above information"));
}
private RestTemplate getRestTemplate() { private RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
......
...@@ -32,10 +32,8 @@ import org.springframework.context.ConfigurableApplicationContext; ...@@ -32,10 +32,8 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ResourceUtils; import org.springframework.util.ResourceUtils;
/** /**
...@@ -108,17 +106,6 @@ public class LoggingApplicationContextInitializer implements ...@@ -108,17 +106,6 @@ public class LoggingApplicationContextInitializer implements
LoggingSystem loggingSystem = LoggingSystem.get(springApplication.getClass() LoggingSystem loggingSystem = LoggingSystem.get(springApplication.getClass()
.getClassLoader()); .getClassLoader());
loggingSystem.beforeInitialize(); loggingSystem.beforeInitialize();
if (this.parseArgs && this.springBootLogging == null
&& !ObjectUtils.isEmpty(args)) {
SimpleCommandLinePropertySource parsedArgs = new SimpleCommandLinePropertySource(
args);
if (parsedArgs.containsProperty("debug")) {
this.springBootLogging = LogLevel.DEBUG;
}
if (parsedArgs.containsProperty("trace")) {
this.springBootLogging = LogLevel.TRACE;
}
}
} }
/** /**
...@@ -130,6 +117,15 @@ public class LoggingApplicationContextInitializer implements ...@@ -130,6 +117,15 @@ public class LoggingApplicationContextInitializer implements
ConfigurableEnvironment environment = applicationContext.getEnvironment(); ConfigurableEnvironment environment = applicationContext.getEnvironment();
if (this.parseArgs && this.springBootLogging == null) {
if (environment.containsProperty("debug")) {
this.springBootLogging = LogLevel.DEBUG;
}
if (environment.containsProperty("trace")) {
this.springBootLogging = LogLevel.TRACE;
}
}
for (Map.Entry<String, String> mapping : ENVIRONMENT_SYSTEM_PROPERTY_MAPPING for (Map.Entry<String, String> mapping : ENVIRONMENT_SYSTEM_PROPERTY_MAPPING
.entrySet()) { .entrySet()) {
if (environment.containsProperty(mapping.getKey())) { if (environment.containsProperty(mapping.getKey())) {
......
...@@ -132,7 +132,7 @@ public class LoggingApplicationContextInitializerTests { ...@@ -132,7 +132,7 @@ public class LoggingApplicationContextInitializerTests {
@Test @Test
public void parseDebugArg() throws Exception { public void parseDebugArg() throws Exception {
this.initializer.initialize(this.springApplication, new String[] { "--debug" }); TestUtils.addEnviroment(this.context, "debug");
this.initializer.initialize(this.context); this.initializer.initialize(this.context);
this.logger.debug("testatdebug"); this.logger.debug("testatdebug");
this.logger.trace("testattrace"); this.logger.trace("testattrace");
...@@ -142,8 +142,7 @@ public class LoggingApplicationContextInitializerTests { ...@@ -142,8 +142,7 @@ public class LoggingApplicationContextInitializerTests {
@Test @Test
public void parseTraceArg() throws Exception { public void parseTraceArg() throws Exception {
this.context = new GenericApplicationContext(); TestUtils.addEnviroment(this.context, "trace");
this.initializer.initialize(this.springApplication, new String[] { "--trace" });
this.initializer.initialize(this.context); this.initializer.initialize(this.context);
this.logger.debug("testatdebug"); this.logger.debug("testatdebug");
this.logger.trace("testattrace"); this.logger.trace("testattrace");
......
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