diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java index d0d77a9828..9d6efedd13 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcChildContextConfiguration.java @@ -121,7 +121,8 @@ public class EndpointWebMvcChildContextConfiguration { @Bean public ManagementErrorEndpoint errorEndpoint(ServerProperties serverProperties, final ErrorAttributes errorAttributes) { - return new ManagementErrorEndpoint(serverProperties.getError().getPath(), errorAttributes); + return new ManagementErrorEndpoint(serverProperties.getError().getPath(), + errorAttributes); } /** diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java index 11fb145689..47db4d8874 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointMvcAdapter.java @@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.ResponseBody; public class EndpointMvcAdapter implements MvcEndpoint { private final Endpoint delegate; + private String path; /** @@ -59,16 +60,16 @@ public class EndpointMvcAdapter implements MvcEndpoint { @Override public String getPath() { - return this.path != null ? this.path : "/" + this.delegate.getId(); + return (this.path != null ? this.path : "/" + this.delegate.getId()); } public void setPath(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } while (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } + if (!path.startsWith("/")) { + path = "/" + path; + } this.path = path; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java index 7d82d4a7fd..ea528ce1bc 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpoint.java @@ -134,9 +134,8 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware { public Object invoke(Principal principal) { if (!this.delegate.isEnabled()) { // Shouldn't happen because the request mapping should not be registered - return new ResponseEntity>( - Collections.singletonMap("message", "This endpoint is disabled"), - HttpStatus.NOT_FOUND); + return new ResponseEntity>(Collections.singletonMap( + "message", "This endpoint is disabled"), HttpStatus.NOT_FOUND); } Health health = getHealth(principal); HttpStatus status = getStatus(health); @@ -187,21 +186,24 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware { if (principal == null || principal.getClass().getName().contains("Anonymous")) { return false; } - if (!ClassUtils.isPresent("org.springframework.security.core.Authentication", - null) || !(principal instanceof Authentication)) { - return false; - } - String role = this.roleResolver.getProperty("role", "ROLE_ADMIN"); - Authentication authentication = (Authentication) principal; - for (GrantedAuthority authority : authentication.getAuthorities()) { - String name = authority.getAuthority(); - if (role.equals(name) || ("ROLE_" + role).equals(name)) { - return true; + if (isSpringSecurityAuthentication(principal)) { + Authentication authentication = (Authentication) principal; + String role = this.roleResolver.getProperty("role", "ROLE_ADMIN"); + for (GrantedAuthority authority : authentication.getAuthorities()) { + String name = authority.getAuthority(); + if (role.equals(name) || ("ROLE_" + role).equals(name)) { + return true; + } } } return false; } + private boolean isSpringSecurityAuthentication(Principal principal) { + return ClassUtils.isPresent("org.springframework.security.core.Authentication", + null) && (principal instanceof Authentication); + } + private boolean isUnrestricted() { Boolean sensitive = this.propertyResolver.getProperty("sensitive", Boolean.class); return !this.secure && !Boolean.TRUE.equals(sensitive); @@ -209,16 +211,16 @@ public class HealthMvcEndpoint implements MvcEndpoint, EnvironmentAware { @Override public String getPath() { - return this.path != null ? this.path : "/" + this.delegate.getId(); + return (this.path != null ? this.path : "/" + this.delegate.getId()); } public void setPath(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } while (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } + if (!path.startsWith("/")) { + path = "/" + path; + } this.path = path; } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java index de0e9fa0bf..5e9c1dea6e 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpoints.java @@ -58,14 +58,13 @@ public class MvcEndpoints implements ApplicationContextAware, InitializingBean { this.endpoints.addAll(existing); this.customTypes = findEndpointClasses(existing); @SuppressWarnings("rawtypes") - Collection delegates = BeanFactoryUtils - .beansOfTypeIncludingAncestors(this.applicationContext, Endpoint.class) - .values(); + Collection delegates = BeanFactoryUtils.beansOfTypeIncludingAncestors( + this.applicationContext, Endpoint.class).values(); for (Endpoint endpoint : delegates) { if (isGenericEndpoint(endpoint.getClass()) && endpoint.isEnabled()) { EndpointMvcAdapter adapter = new EndpointMvcAdapter(endpoint); - String path = this.applicationContext.getEnvironment() - .getProperty("endpoints." + endpoint.getId() + ".path"); + String path = this.applicationContext.getEnvironment().getProperty( + "endpoints." + endpoint.getId() + ".path"); if (path != null) { adapter.setPath(path); } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpointTests.java index 33cdf087da..9f111c59bb 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HealthMvcEndpointTests.java @@ -98,10 +98,10 @@ public class HealthMvcEndpointTests { @Test @SuppressWarnings("unchecked") public void customMapping() { - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().status("OK").build()); - this.mvc.setStatusMapping( - Collections.singletonMap("OK", HttpStatus.INTERNAL_SERVER_ERROR)); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().status("OK").build()); + this.mvc.setStatusMapping(Collections.singletonMap("OK", + HttpStatus.INTERNAL_SERVER_ERROR)); Object result = this.mvc.invoke(null); assertTrue(result instanceof ResponseEntity); ResponseEntity response = (ResponseEntity) result; @@ -112,8 +112,8 @@ public class HealthMvcEndpointTests { @Test @SuppressWarnings("unchecked") public void customMappingWithRelaxedName() { - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().outOfService().build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().outOfService().build()); this.mvc.setStatusMapping(Collections.singletonMap("out-of-service", HttpStatus.INTERNAL_SERVER_ERROR)); Object result = this.mvc.invoke(null); @@ -125,8 +125,8 @@ public class HealthMvcEndpointTests { @Test public void secureEvenWhenNotSensitive() { - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); given(this.endpoint.isSensitive()).willReturn(false); Object result = this.mvc.invoke(this.admin); assertTrue(result instanceof Health); @@ -136,8 +136,8 @@ public class HealthMvcEndpointTests { @Test public void secureNonAdmin() { - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(this.user); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); @@ -148,8 +148,8 @@ public class HealthMvcEndpointTests { public void healthIsCached() { given(this.endpoint.getTimeToLive()).willReturn(10000L); given(this.endpoint.isSensitive()).willReturn(true); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(this.admin); assertTrue(result instanceof Health); Health health = (Health) result; @@ -170,8 +170,8 @@ public class HealthMvcEndpointTests { public void unsecureAnonymousAccessUnrestricted() { this.mvc = new HealthMvcEndpoint(this.endpoint, false); this.mvc.setEnvironment(this.environment); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(null); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); @@ -181,8 +181,8 @@ public class HealthMvcEndpointTests { @Test public void unsensitiveAnonymousAccessRestricted() { this.environment.getPropertySources().addLast(NON_SENSITIVE); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(null); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); @@ -194,8 +194,8 @@ public class HealthMvcEndpointTests { this.mvc = new HealthMvcEndpoint(this.endpoint, false); this.mvc.setEnvironment(this.environment); this.environment.getPropertySources().addLast(NON_SENSITIVE); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(null); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); @@ -205,8 +205,8 @@ public class HealthMvcEndpointTests { @Test public void noCachingWhenTimeToLiveIsZero() { given(this.endpoint.getTimeToLive()).willReturn(0L); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(null); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); @@ -221,8 +221,8 @@ public class HealthMvcEndpointTests { public void newValueIsReturnedOnceTtlExpires() throws InterruptedException { given(this.endpoint.getTimeToLive()).willReturn(50L); given(this.endpoint.isSensitive()).willReturn(false); - given(this.endpoint.invoke()) - .willReturn(new Health.Builder().up().withDetail("foo", "bar").build()); + given(this.endpoint.invoke()).willReturn( + new Health.Builder().up().withDetail("foo", "bar").build()); Object result = this.mvc.invoke(null); assertTrue(result instanceof Health); assertTrue(((Health) result).getStatus() == Status.UP); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointIntegrationTests.java index 2a15a3bbd5..57a620ff70 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointIntegrationTests.java @@ -182,8 +182,8 @@ public class MvcEndpointIntegrationTests { EnvironmentTestUtils.addEnvironment(this.context, "spring.jackson.serialization.indent-output:true"); MockMvc mockMvc = createMockMvc(); - mockMvc.perform(get("/beans")) - .andExpect(content().string(startsWith("{" + LINE_SEPARATOR))); + mockMvc.perform(get("/beans")).andExpect( + content().string(startsWith("{" + LINE_SEPARATOR))); } private MockMvc createMockMvc() { @@ -205,8 +205,8 @@ public class MvcEndpointIntegrationTests { } @ImportAutoConfiguration({ JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class, - EndpointWebMvcAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class }) static class DefaultConfiguration { @@ -224,8 +224,8 @@ public class MvcEndpointIntegrationTests { @ImportAutoConfiguration({ HypermediaAutoConfiguration.class, RepositoryRestMvcAutoConfiguration.class, JacksonAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, EndpointAutoConfiguration.class, - EndpointWebMvcAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + EndpointAutoConfiguration.class, EndpointWebMvcAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, WebMvcAutoConfiguration.class }) static class SpringDataRestConfiguration { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java index d3d8bce645..7f005564e2 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/MvcEndpointsTests.java @@ -65,15 +65,15 @@ public class MvcEndpointsTests { @Test public void changesPath() throws Exception { - EnvironmentTestUtils.addEnvironment(this.context, - "endpoints.test.path=/foo/bar/"); + EnvironmentTestUtils + .addEnvironment(this.context, "endpoints.test.path=/foo/bar/"); this.context.getDefaultListableBeanFactory().registerSingleton("endpoint", new TestEndpoint()); this.endpoints.setApplicationContext(this.context); this.endpoints.afterPropertiesSet(); assertEquals(1, this.endpoints.getEndpoints().size()); - assertEquals("/foo/bar", - this.endpoints.getEndpoints().iterator().next().getPath()); + assertEquals("/foo/bar", this.endpoints.getEndpoints().iterator().next() + .getPath()); } protected static class TestEndpoint extends AbstractEndpoint { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DataSourceHealthIndicatorTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DataSourceHealthIndicatorTests.java index 39af41d647..5dbcc11d8f 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DataSourceHealthIndicatorTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/DataSourceHealthIndicatorTests.java @@ -99,8 +99,8 @@ public class DataSourceHealthIndicatorTests { public void connectionClosed() throws Exception { DataSource dataSource = mock(DataSource.class); Connection connection = mock(Connection.class); - given(connection.getMetaData()) - .willReturn(this.dataSource.getConnection().getMetaData()); + given(connection.getMetaData()).willReturn( + this.dataSource.getConnection().getMetaData()); given(dataSource.getConnection()).willReturn(connection); this.indicator.setDataSource(dataSource); Health health = this.indicator.health(); diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java index 32d9e09a28..7792aa13bf 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java @@ -88,7 +88,8 @@ public class VelocityAutoConfiguration { factory.setResourceLoaderPath(this.properties.getResourceLoaderPath()); factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess()); Properties velocityProperties = new Properties(); - velocityProperties.setProperty("input.encoding", this.properties.getCharsetName()); + velocityProperties.setProperty("input.encoding", + this.properties.getCharsetName()); velocityProperties.putAll(this.properties.getProperties()); factory.setVelocityProperties(velocityProperties); } diff --git a/spring-boot-devtools/src/test/resources/user-home/.spring-boot-devtools.properties b/spring-boot-devtools/src/test/resources/user-home/.spring-boot-devtools.properties index d44c1c6a66..c0504825e7 100644 --- a/spring-boot-devtools/src/test/resources/user-home/.spring-boot-devtools.properties +++ b/spring-boot-devtools/src/test/resources/user-home/.spring-boot-devtools.properties @@ -1 +1 @@ -spring.thymeleaf.cache=true \ No newline at end of file +spring.thymeleaf.cache=true diff --git a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc index c11f95c387..67536f4ace 100644 --- a/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/production-ready-features.adoc @@ -513,23 +513,21 @@ your application might already use `/info` for another purpose. You can use the The `application.properties` example above will change the endpoint from `/{id}` to `/manage/{id}` (e.g. `/manage/info`). -You can also change the "id" of an endpoint (using -`endpoints.{name}.id`) which then changes the default resource path -for the MVC endpoint. Legal endpoint ids are composed only of -alphanumeric characters (because they can be exposed in a number of -places, including JMX object names, where special characters are -forbidden). The MVC path can be changed separately by configuring -`endpoints.{name}.path`, and there is no validation on those values -(so you can use anything that is legel in a URL path). For example, to -change the location of the `/health` endpoint to `/ping/me` you can -set `endpoints.health.path=/ping/me`. +You can also change the "`id`" of an endpoint (using `endpoints.{name}.id`) which then +changes the default resource path for the MVC endpoint. Legal endpoint ids are composed +only of alphanumeric characters (because they can be exposed in a number of places, +including JMX object names, where special characters are forbidden). The MVC path can be +changed separately by configuring `endpoints.{name}.path`, and there is no validation on +those values (so you can use anything that is legel in a URL path). For example, to change +the location of the `/health` endpoint to `/ping/me` you can set +`endpoints.health.path=/ping/me`. + +TIP: If you provide a custom `MvcEndpoint` remember to include a settable `path` property, +and default it to `/{id}` if you want your code to behave like the standard MVC endpoints. +(Take a look at the `HealthMvcEndpoint` to see how you might do that.) If your custom +endpoint is an `Endpoint` (not an `MvcEndpoint`) then Spring Boot will take care of the +path for you. -TIP: If you provide a custom `MvcEndpoint` remember to include a -settable `path` property, and default it to `/{id}` if you want your -code to behave like the standard MVC endpoints. (Take a look at the -`HealthMvcEndpoint` to see how you might do that.) If your custom -endpoint is an `Endpoint` (not an `MvcEndpoint`) then Spring Boot will -take care of the path for you. [[production-ready-customizing-management-server-port]] @@ -1073,10 +1071,11 @@ values for specific `MetricWriters` can be set as `spring.metrics.export.triggers..*` where `` is a bean name (or pattern for matching bean names). -WARNING: The automatic export of metrics is disabled if you switch off the -default `MetricRepository` (e.g. by using Dropwizard metrics). You can get back the -same functionality be declaring a bean of your own of type `MetricReader` and -declaring it to be `@ExportMetricReader`. +WARNING: The automatic export of metrics is disabled if you switch off the default +`MetricRepository` (e.g. by using Dropwizard metrics). You can get back the same +functionality be declaring a bean of your own of type `MetricReader` and declaring it to +be `@ExportMetricReader`. + [[production-ready-metric-writers-export-to-redis]] diff --git a/spring-boot-samples/spring-boot-sample-secure-sso/src/main/java/sample/secure/sso/SampleOAuth2SsoApplication.java b/spring-boot-samples/spring-boot-sample-secure-sso/src/main/java/sample/secure/sso/SampleOAuth2SsoApplication.java index fd709ad75a..f692ac037e 100644 --- a/spring-boot-samples/spring-boot-sample-secure-sso/src/main/java/sample/secure/sso/SampleOAuth2SsoApplication.java +++ b/spring-boot-samples/spring-boot-sample-secure-sso/src/main/java/sample/secure/sso/SampleOAuth2SsoApplication.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package sample.secure.sso; import org.springframework.boot.SpringApplication; @@ -23,7 +24,7 @@ import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth * After you launch the app it should prompt you for login with github. As long as it runs * on port 8080 on localhost it should work. Use an incognito window for testing * (otherwise you might find you are already authenticated). - * + * * @author Dave Syer */ @SpringBootApplication diff --git a/spring-boot-samples/spring-boot-sample-secure-sso/src/main/resources/static/index.html b/spring-boot-samples/spring-boot-sample-secure-sso/src/main/resources/static/index.html index 03a317ed60..d7affc9e2e 100644 --- a/spring-boot-samples/spring-boot-sample-secure-sso/src/main/resources/static/index.html +++ b/spring-boot-samples/spring-boot-sample-secure-sso/src/main/resources/static/index.html @@ -7,8 +7,7 @@ href="webjars/bootstrap/3.0.3/css/bootstrap.min.css" /> - +