This commit is contained in:
Phillip Webb 2014-10-28 16:34:57 -07:00
parent 466ed469eb
commit d17b7c8195
19 changed files with 131 additions and 116 deletions

View File

@ -22,7 +22,9 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for some health properties
*
* @author Christian Dupuis
* @since 1.2.0
*/
@ConfigurationProperties("health.status")
public class HealthIndicatorAutoConfigurationProperties {

View File

@ -142,8 +142,8 @@ public class ManagementSecurityAutoConfiguration {
List<String> ignored = SpringBootWebSecurityConfiguration
.getIgnored(this.security);
if (!this.management.getSecurity().isEnabled()) {
ignored.addAll(Arrays.asList(getEndpointPaths(
this.endpointHandlerMapping)));
ignored.addAll(Arrays
.asList(getEndpointPaths(this.endpointHandlerMapping)));
}
if (ignored.contains("none")) {
ignored.remove("none");
@ -227,11 +227,10 @@ public class ManagementSecurityAutoConfiguration {
http.exceptionHandling().authenticationEntryPoint(entryPoint());
paths = this.server.getPathsArray(paths);
http.requestMatchers().antMatchers(paths);
// @formatter:off
http.authorizeRequests()
.antMatchers(this.server.getPathsArray(getEndpointPaths(this.endpointHandlerMapping, false))).access("permitAll()")
String[] endpointPaths = this.server.getPathsArray(getEndpointPaths(
this.endpointHandlerMapping, false));
http.authorizeRequests().antMatchers(endpointPaths).access("permitAll()")
.anyRequest().hasRole(this.management.getSecurity().getRole());
// @formatter:on
http.httpBasic();
// No cookies for management endpoints by default

View File

@ -36,20 +36,19 @@ public class HealthEndpoint extends AbstractEndpoint<Health> {
private final HealthIndicator healthIndicator;
private long ttl = 1000;
private long timeToLive = 1000;
/**
* Time to live for cached result. If accessed anonymously, we might need to cache the
* result of this endpoint to prevent a DOS attack.
*
* @return time to live in milliseconds (default 1000)
*/
public long getTtl() {
return ttl;
public long getTimeToLive() {
return this.timeToLive;
}
public void setTtl(long ttl) {
this.ttl = ttl;
public void setTimeToLive(long ttl) {
this.timeToLive = ttl;
}
/**

View File

@ -18,8 +18,9 @@ package org.springframework.boot.actuate.endpoint.mvc;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@ -52,7 +53,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
public class EndpointHandlerMapping extends RequestMappingHandlerMapping implements
ApplicationContextAware {
private final Map<String, MvcEndpoint> endpoints = new HashMap<String, MvcEndpoint>();
private final Map<String, MvcEndpoint> endpoints;
private String prefix = "";
@ -64,15 +65,21 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping impleme
* @param endpoints
*/
public EndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
HashMap<String, MvcEndpoint> map = (HashMap<String, MvcEndpoint>) this.endpoints;
for (MvcEndpoint endpoint : endpoints) {
map.put(endpoint.getPath(), endpoint);
}
this.endpoints = buildEndpointsMap(endpoints);
// By default the static resource handler mapping is LOWEST_PRECEDENCE - 1
// and the RequestMappingHandlerMapping is 0 (we ideally want to be before both)
setOrder(-100);
}
private Map<String, MvcEndpoint> buildEndpointsMap(
Collection<? extends MvcEndpoint> endpoints) {
Map<String, MvcEndpoint> map = new LinkedHashMap<String, MvcEndpoint>();
for (MvcEndpoint endpoint : endpoints) {
map.put(endpoint.getPath(), endpoint);
}
return Collections.unmodifiableMap(map);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();

View File

@ -101,29 +101,26 @@ public class HealthMvcEndpoint implements MvcEndpoint {
@RequestMapping
@ResponseBody
public Object invoke(Principal principal) {
if (!delegate.isEnabled()) {
if (!this.delegate.isEnabled()) {
// Shouldn't happen because the request mapping should not be registered
return new ResponseEntity<Map<String, String>>(Collections.singletonMap(
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
}
Health health = getHealth(principal);
Status status = health.getStatus();
if (this.statusMapping.containsKey(status.getCode())) {
return new ResponseEntity<Health>(health, this.statusMapping.get(status
.getCode()));
}
return health;
}
private Health getHealth(Principal principal) {
Health health = useCachedValue(principal) ? cached : (Health) delegate.invoke();
Health health = (useCachedValue(principal) ? this.cached : (Health) this.delegate
.invoke());
// Not too worried about concurrent access here, the worst that can happen is the
// odd extra call to delegate.invoke()
cached = health;
this.cached = health;
if (!secure(principal)) {
// If not secure we only expose the status
health = Health.status(health.getStatus()).build();
@ -137,12 +134,12 @@ public class HealthMvcEndpoint implements MvcEndpoint {
private boolean useCachedValue(Principal principal) {
long currentAccess = System.currentTimeMillis();
if (cached == null || secure(principal)
|| currentAccess - lastAccess > delegate.getTtl()) {
lastAccess = currentAccess;
if (this.cached == null || secure(principal)
|| (currentAccess - this.lastAccess) > this.delegate.getTimeToLive()) {
this.lastAccess = currentAccess;
return false;
}
return cached != null;
return this.cached != null;
}
@Override

View File

@ -72,7 +72,7 @@ public class ConfigurationPropertiesReportEndpointTests extends
@SuppressWarnings("unchecked")
public void testKeySanitization() throws Exception {
ConfigurationPropertiesReportEndpoint report = getEndpointBean();
report.setKeysToSanitize(new String[] { "property" });
report.setKeysToSanitize("property");
Map<String, Object> properties = report.invoke();
Map<String, Object> nestedProperties = (Map<String, Object>) ((Map<String, Object>) properties
.get("testProperties")).get("properties");

View File

@ -16,11 +16,6 @@
package org.springframework.boot.actuate.endpoint.mvc;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import java.util.Collections;
import org.junit.Before;
@ -33,10 +28,16 @@ import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link HealthMvcEndpoint}.
*
* @author Christian Dupuis
* @author Dave Syer
*/
public class HealthMvcEndpointTests {
@ -92,7 +93,7 @@ public class HealthMvcEndpointTests {
public void secure() {
given(this.endpoint.invoke()).willReturn(
new Health.Builder().up().withDetail("foo", "bar").build());
Object result = this.mvc.invoke(user);
Object result = this.mvc.invoke(this.user);
assertTrue(result instanceof Health);
assertTrue(((Health) result).getStatus() == Status.UP);
assertEquals("bar", ((Health) result).getDetails().get("foo"));
@ -100,25 +101,25 @@ public class HealthMvcEndpointTests {
@Test
public void secureNotCached() {
given(this.endpoint.getTtl()).willReturn(10000L);
given(this.endpoint.getTimeToLive()).willReturn(10000L);
given(this.endpoint.invoke()).willReturn(
new Health.Builder().up().withDetail("foo", "bar").build());
Object result = this.mvc.invoke(user);
Object result = this.mvc.invoke(this.user);
assertTrue(result instanceof Health);
assertTrue(((Health) result).getStatus() == Status.UP);
given(this.endpoint.invoke()).willReturn(new Health.Builder().down().build());
result = this.mvc.invoke(user);
result = this.mvc.invoke(this.user);
@SuppressWarnings("unchecked")
Health health = (Health) ((ResponseEntity<Health>) result).getBody();
Health health = ((ResponseEntity<Health>) result).getBody();
assertTrue(health.getStatus() == Status.DOWN);
}
@Test
public void unsecureCached() {
given(this.endpoint.getTtl()).willReturn(10000L);
given(this.endpoint.getTimeToLive()).willReturn(10000L);
given(this.endpoint.invoke()).willReturn(
new Health.Builder().up().withDetail("foo", "bar").build());
Object result = this.mvc.invoke(user);
Object result = this.mvc.invoke(this.user);
assertTrue(result instanceof Health);
assertTrue(((Health) result).getStatus() == Status.UP);
given(this.endpoint.invoke()).willReturn(new Health.Builder().down().build());

View File

@ -26,6 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*
* @author Oliver Gierke
* @author Stephane Nicoll
* @since 1.2.0
*/
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
@ -43,7 +44,7 @@ public class MailProperties {
private Map<String, String> properties = new HashMap<String, String>();
public String getHost() {
return host;
return this.host;
}
public void setHost(String host) {
@ -51,7 +52,7 @@ public class MailProperties {
}
public Integer getPort() {
return port;
return this.port;
}
public void setPort(Integer port) {
@ -59,7 +60,7 @@ public class MailProperties {
}
public String getUsername() {
return username;
return this.username;
}
public void setUsername(String username) {
@ -67,7 +68,7 @@ public class MailProperties {
}
public String getPassword() {
return password;
return this.password;
}
public void setPassword(String password) {
@ -75,7 +76,7 @@ public class MailProperties {
}
public String getDefaultEncoding() {
return defaultEncoding;
return this.defaultEncoding;
}
public void setDefaultEncoding(String defaultEncoding) {
@ -83,7 +84,7 @@ public class MailProperties {
}
public Map<String, String> getProperties() {
return properties;
return this.properties;
}
}

View File

@ -16,8 +16,8 @@
package org.springframework.boot.autoconfigure.mail;
import java.util.Map;
import java.util.Properties;
import javax.activation.MimeType;
import javax.mail.internet.MimeMessage;
@ -38,15 +38,17 @@ import org.springframework.mail.javamail.JavaMailSenderImpl;
*
* @author Oliver Gierke
* @author Stephane Nicoll
* @sicne 1.2.0
*/
@Configuration
@ConditionalOnClass({MimeMessage.class, MimeType.class})
@ConditionalOnClass({ MimeMessage.class, MimeType.class })
@ConditionalOnProperty(prefix = "spring.mail", value = "host")
@ConditionalOnMissingBean(MailSender.class)
@EnableConfigurationProperties(MailProperties.class)
public class MailSenderAutoConfiguration {
@Autowired MailProperties properties;
@Autowired
MailProperties properties;
@Bean
public JavaMailSender mailSender() {
@ -58,15 +60,12 @@ public class MailSenderAutoConfiguration {
sender.setUsername(this.properties.getUsername());
sender.setPassword(this.properties.getPassword());
sender.setDefaultEncoding(this.properties.getDefaultEncoding());
Map<String,String> properties = this.properties.getProperties();
if (!properties.isEmpty()) {
Properties javaMailProperties= new Properties();
for (Map.Entry<String, String> entry : properties.entrySet()) {
javaMailProperties.setProperty(entry.getKey(), entry.getValue());
}
sender.setJavaMailProperties(javaMailProperties);
if (!this.properties.getProperties().isEmpty()) {
Properties properties = new Properties();
properties.putAll(this.properties.getProperties());
sender.setJavaMailProperties(properties);
}
return sender;
}
}
}

View File

@ -75,7 +75,6 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
private void storeErrorAttributes(HttpServletRequest request, Exception ex) {
request.setAttribute(ERROR_ATTRIBUTE, ex);
}
@Override
@ -122,7 +121,8 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
}
}
Object message = getAttribute(requestAttributes, "javax.servlet.error.message");
if ((message != null || errorAttributes.get("message") == null) && !(error instanceof BindingResult)) {
if ((message != null || errorAttributes.get("message") == null)
&& !(error instanceof BindingResult)) {
errorAttributes.put("message", message == null ? "No message available"
: message);
}

View File

@ -20,7 +20,6 @@ import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@ -28,7 +27,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Tests for {@link MailSenderAutoConfiguration}.
@ -53,7 +53,8 @@ public class MailSenderAutoConfigurationTests {
public void smtpHostSet() {
String host = "192.168.1.234";
load(EmptyConfig.class, "spring.mail.host:" + host);
JavaMailSenderImpl bean = (JavaMailSenderImpl) context.getBean(JavaMailSender.class);
JavaMailSenderImpl bean = (JavaMailSenderImpl) this.context
.getBean(JavaMailSender.class);
assertEquals(host, bean.getHost());
}
@ -61,8 +62,10 @@ public class MailSenderAutoConfigurationTests {
public void smptHostWithSettings() {
String host = "192.168.1.234";
load(EmptyConfig.class, "spring.mail.host:" + host, "spring.mail.port:42",
"spring.mail.username:john", "spring.mail.password:secret", "spring.mail.default-encoding:ISO-9");
JavaMailSenderImpl bean = (JavaMailSenderImpl) context.getBean(JavaMailSender.class);
"spring.mail.username:john", "spring.mail.password:secret",
"spring.mail.default-encoding:ISO-9");
JavaMailSenderImpl bean = (JavaMailSenderImpl) this.context
.getBean(JavaMailSender.class);
assertEquals(host, bean.getHost());
assertEquals(42, bean.getPort());
assertEquals("john", bean.getUsername());
@ -72,29 +75,31 @@ public class MailSenderAutoConfigurationTests {
@Test
public void smptHostWithJavaMailProperties() {
load(EmptyConfig.class, "spring.mail.host:localhost", "spring.mail.properties.mail.smtp.auth:true");
JavaMailSenderImpl bean = (JavaMailSenderImpl) context.getBean(JavaMailSender.class);
load(EmptyConfig.class, "spring.mail.host:localhost",
"spring.mail.properties.mail.smtp.auth:true");
JavaMailSenderImpl bean = (JavaMailSenderImpl) this.context
.getBean(JavaMailSender.class);
assertEquals("true", bean.getJavaMailProperties().get("mail.smtp.auth"));
}
@Test
public void smtpHostNotSet() {
load(EmptyConfig.class);
assertEquals(0, context.getBeansOfType(JavaMailSender.class).size());
assertEquals(0, this.context.getBeansOfType(JavaMailSender.class).size());
}
@Test
public void mailSenderBackOff() {
load(ManualMailConfiguration.class, "spring.mail.host:smtp.acme.org",
"spring.mail.user:user", "spring.mail.password:secret");
JavaMailSenderImpl bean = (JavaMailSenderImpl) context.getBean(JavaMailSender.class);
JavaMailSenderImpl bean = (JavaMailSenderImpl) this.context
.getBean(JavaMailSender.class);
assertNull(bean.getUsername());
assertNull(bean.getPassword());
}
private void load(Class<?> config, String... environment) {
this.context = doLoad(new Class<?>[] {config}, environment);
this.context = doLoad(new Class<?>[] { config }, environment);
}
private AnnotationConfigApplicationContext doLoad(Class<?>[] configs,
@ -119,5 +124,7 @@ public class MailSenderAutoConfigurationTests {
JavaMailSender customMailSender() {
return new JavaMailSenderImpl();
}
}
}

View File

@ -120,7 +120,8 @@ public class DefaultErrorAttributesTests {
@Test
public void nullMessage() throws Exception {
this.request.setAttribute("javax.servlet.error.exception", new RuntimeException());
this.request
.setAttribute("javax.servlet.error.exception", new RuntimeException());
this.request.setAttribute("javax.servlet.error.message", "Test");
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(
this.requestAttributes, false);

View File

@ -374,6 +374,7 @@ content into your application; rather pick only the properties that you need.
endpoints.health.id=health
endpoints.health.sensitive=false
endpoints.health.enabled=true
endpoints.health.time-to-live=1000
endpoints.info.id=info
endpoints.info.sensitive=false
endpoints.info.enabled=true

View File

@ -1564,28 +1564,29 @@ would only ever be a development time trick probably).
[[howto-reload-springloaded-maven]]
==== Configuring Spring Loaded for use with Maven
To use Spring Loaded with the Maven command line, just add it as a dependency in the
To use Spring Loaded with the Maven command line, just add it as a dependency in the
Spring Boot plugin declaration, e.g.
.pom.xml
[source,xml,indent=0]
----
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.0.RELEASE</version>
</dependency>
</dependencies>
</plugin>
----
This normally works pretty well with Eclipse and IntelliJ as long as
they have their build configuration aligned with the Maven defaults
(Eclipse m2e does this out of the box).
This normally works pretty well with Eclipse and IntelliJ as long as they have their
build configuration aligned with the Maven defaults (Eclipse m2e does this out of the
box).
[[howto-reload-springloaded-gradle-and-intellij]]
==== Configuring Spring Loaded for use with Gradle and IntelliJ

View File

@ -94,26 +94,30 @@ Here is an example "`hello world`" web application written in Groovy:
}
----
Then
To compile and run the application type:
[indent=0,subs="verbatim,quotes,attributes"]
----
$ spring run hello.groovy
$ spring run hello.groovy
----
To pass command line arguments to the application, you need to use a
"--" to separate them from the "spring" command arguments, e.g.
To pass command line arguments to the application, you need to use a `--` to separate
them from the "`spring`" command arguments, e.g.
[indent=0,subs="verbatim,quotes,attributes"]
----
$ spring run hello.groovy -- --server.port=9000
$ spring run hello.groovy -- --server.port=9000
----
and to set JVM command line arguments you can use the `JAVA_OPTS`
environment variable, e.g.
To set JVM command line arguments you can use the `JAVA_OPTS` environment variable, e.g.
[indent=0,subs="verbatim,quotes,attributes"]
----
$ JAVA_OPTS=-Xmx1024m spring run hello.groovy
$ JAVA_OPTS=-Xmx1024m spring run hello.groovy
----
[[cli-install-uninstall]]
=== Adding dependencies to the CLI
You can add dependencies to the CLI using the `install` command. The command takes one

View File

@ -138,8 +138,8 @@ public class SampleActuatorApplicationTests {
@Test
public void testSecureHealth() throws Exception {
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword()).getForEntity(
"http://localhost:" + this.port + "/health", String.class);
ResponseEntity<String> entity = new TestRestTemplate("user", getPassword())
.getForEntity("http://localhost:" + this.port + "/health", String.class);
assertEquals(HttpStatus.OK, entity.getStatusCode());
assertTrue("Wrong body: " + entity.getBody(),
entity.getBody().contains("\"hello\":1"));

View File

@ -70,7 +70,7 @@ import org.springframework.util.StringUtils;
* vcap.application.version: 0138c4a6-2a73-416b-aca0-572c09f7ca53
* vcap.application.name: foo
* vcap.application.uris[0]: foo.cfapps.io
*
*
* vcap.services.mysql.name: mysql
* vcap.services.mysql.label: rds-mysql-1.0
* vcap.services.mysql.credentials.name: d04fb13d27d964c62b267bbba1cffb9da
@ -112,13 +112,11 @@ public class VcapApplicationListener implements
@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment environment = event.getEnvironment();
if (!environment.containsProperty(VCAP_APPLICATION)
&& !environment.containsProperty(VCAP_SERVICES)) {
return;
}
Properties properties = new Properties();
addWithPrefix(properties, getPropertiesFromApplication(environment),
"vcap.application.");
@ -130,12 +128,10 @@ public class VcapApplicationListener implements
propertySources.addAfter(
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
new PropertiesPropertySource("vcap", properties));
}
else {
propertySources.addFirst(new PropertiesPropertySource("vcap", properties));
}
}
private void addWithPrefix(Properties properties, Properties other, String prefix) {

View File

@ -16,15 +16,6 @@
package org.springframework.boot.builder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
@ -43,6 +34,15 @@ import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link SpringApplicationBuilder}.
*

View File

@ -16,9 +16,6 @@
package org.springframework.boot.cloudfoundry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
@ -26,6 +23,9 @@ import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* Tests for {@link VcapApplicationListener}.
*