pull/11690/merge
Phillip Webb 7 years ago
parent 6d93573db0
commit f3379668ac

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -61,6 +61,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.integration.config.EnableIntegrationManagement; import org.springframework.integration.config.EnableIntegrationManagement;
import org.springframework.integration.support.management.IntegrationManagementConfigurer; import org.springframework.integration.support.management.IntegrationManagementConfigurer;
import org.springframework.util.Assert;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics. * {@link EnableAutoConfiguration Auto-configuration} for Micrometer-based metrics.
@ -96,10 +97,8 @@ public class MetricsAutoConfiguration {
.forEach((configurer) -> configurer.configureRegistry(composite)); .forEach((configurer) -> configurer.configureRegistry(composite));
exporters.getIfAvailable(Collections::emptyList).forEach((exporter) -> { exporters.getIfAvailable(Collections::emptyList).forEach((exporter) -> {
MeterRegistry childRegistry = exporter.registry(); MeterRegistry childRegistry = exporter.registry();
if (composite == childRegistry) { Assert.state(composite != childRegistry,
throw new IllegalStateException( "cannot add a CompositeMeterRegistry to itself");
"cannot add a CompositeMeterRegistry to itself");
}
composite.add(childRegistry); composite.add(childRegistry);
}); });
return composite; return composite;

@ -80,7 +80,8 @@ public class RabbitMetricsConfiguration {
private String getConnectionFactoryName(String beanName) { private String getConnectionFactoryName(String beanName) {
if (beanName.length() > CONNECTION_FACTORY_SUFFIX.length() if (beanName.length() > CONNECTION_FACTORY_SUFFIX.length()
&& StringUtils.endsWithIgnoreCase(beanName, CONNECTION_FACTORY_SUFFIX)) { && StringUtils.endsWithIgnoreCase(beanName, CONNECTION_FACTORY_SUFFIX)) {
return beanName.substring(0, beanName.length() - CONNECTION_FACTORY_SUFFIX.length()); return beanName.substring(0,
beanName.length() - CONNECTION_FACTORY_SUFFIX.length());
} }
return beanName; return beanName;
} }

@ -96,4 +96,5 @@ public class DatadogProperties extends StepRegistryProperties {
public void setUri(String uri) { public void setUri(String uri) {
this.uri = uri; this.uri = uri;
} }
} }

@ -41,4 +41,5 @@ public class JmxProperties {
public void setStep(Duration step) { public void setStep(Duration step) {
this.step = step; this.step = step;
} }
} }

@ -35,7 +35,7 @@ class JmxPropertiesConfigAdapter extends PropertiesConfigAdapter<JmxProperties>
} }
@Override @Override
public String get(String k) { public String get(String key) {
return null; return null;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -26,7 +26,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for Servlet-specific management * {@link EnableAutoConfiguration Auto-configuration} for Reactive-specific management
* context concerns. * context concerns.
* *
* @author Phillip Webb * @author Phillip Webb

@ -42,7 +42,6 @@ public class RabbitMetricsConfigurationTests {
RabbitAutoConfiguration.class)) RabbitAutoConfiguration.class))
.withPropertyValues("management.metrics.use-global-registry=false"); .withPropertyValues("management.metrics.use-global-registry=false");
@Test @Test
public void autoConfiguredConnectionFactoryIsInstrumented() { public void autoConfiguredConnectionFactoryIsInstrumented() {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
@ -67,14 +66,14 @@ public class RabbitMetricsConfigurationTests {
@Test @Test
public void rabbitmqNativeConnectionFactoryInstrumentationCanBeDisabled() { public void rabbitmqNativeConnectionFactoryInstrumentationCanBeDisabled() {
this.contextRunner this.contextRunner
.withPropertyValues( .withPropertyValues("management.metrics.rabbitmq.instrument=false")
"management.metrics.rabbitmq.instrument=false").run((context) -> { .run((context) -> {
MeterRegistry registry = context.getBean(MeterRegistry.class); MeterRegistry registry = context.getBean(MeterRegistry.class);
assertThat(registry.find("rabbitmq.connections").meter()).isNotPresent(); assertThat(registry.find("rabbitmq.connections").meter())
}); .isNotPresent();
});
} }
@Configuration @Configuration
static class RegistryConfiguration { static class RegistryConfiguration {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -42,7 +42,7 @@ public class RabbitMetrics implements MeterBinder {
private final ConnectionFactory connectionFactory; private final ConnectionFactory connectionFactory;
/** /**
* Create a new meter binder recording the specified {@link ConnectionFactory}. * Create a new meter binder recording the specified {@link ConnectionFactory}.
* @param connectionFactory the {@link ConnectionFactory} to instrument * @param connectionFactory the {@link ConnectionFactory} to instrument
* @param name the name prefix of the metrics * @param name the name prefix of the metrics
* @param tags tags to apply to all recorded metrics * @param tags tags to apply to all recorded metrics
@ -53,13 +53,13 @@ public class RabbitMetrics implements MeterBinder {
Assert.notNull(name, "Name must not be null"); Assert.notNull(name, "Name must not be null");
this.connectionFactory = connectionFactory; this.connectionFactory = connectionFactory;
this.name = name; this.name = name;
this.tags = (tags != null ? tags : Collections.EMPTY_LIST); this.tags = (tags != null ? tags : Collections.emptyList());
} }
@Override @Override
public void bindTo(MeterRegistry registry) { public void bindTo(MeterRegistry registry) {
this.connectionFactory.setMetricsCollector(new MicrometerMetricsCollector( this.connectionFactory.setMetricsCollector(
registry, this.name, this.tags)); new MicrometerMetricsCollector(registry, this.name, this.tags));
} }
} }

@ -45,10 +45,10 @@ public class RabbitMetricsTests {
SimpleMeterRegistry registry = new SimpleMeterRegistry(); SimpleMeterRegistry registry = new SimpleMeterRegistry();
new RabbitMetrics(connectionFactory, "test", Tags.zip("env", "prod")) new RabbitMetrics(connectionFactory, "test", Tags.zip("env", "prod"))
.bindTo(registry); .bindTo(registry);
assertThat(registry.find("test.connections") assertThat(registry.find("test.connections").tags("env", "prod").meter())
.tags("env", "prod").meter()).isPresent(); .isPresent();
assertThat(registry.find("test.connections") assertThat(registry.find("test.connections").tags("env", "dev").meter())
.tags("env", "dev").meter()).isNotPresent(); .isNotPresent();
} }
private ConnectionFactory mockConnectionFactory() { private ConnectionFactory mockConnectionFactory() {

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -62,7 +62,6 @@ public final class JettyCustomizer {
if (jettyProperties.getMaxHttpPostSize() > 0) { if (jettyProperties.getMaxHttpPostSize() > 0) {
customizeMaxHttpPostSize(factory, jettyProperties.getMaxHttpPostSize()); customizeMaxHttpPostSize(factory, jettyProperties.getMaxHttpPostSize());
} }
if (serverProperties.getConnectionTimeout() != null) { if (serverProperties.getConnectionTimeout() != null) {
customizeConnectionTimeout(factory, serverProperties.getConnectionTimeout()); customizeConnectionTimeout(factory, serverProperties.getConnectionTimeout());
} }
@ -176,4 +175,5 @@ public final class JettyCustomizer {
server.setRequestLog(log); server.setRequestLog(log);
}); });
} }
} }

@ -197,7 +197,6 @@ public final class TomcatCustomizer {
private static void customizeAccessLog(ServerProperties.Tomcat tomcatProperties, private static void customizeAccessLog(ServerProperties.Tomcat tomcatProperties,
ConfigurableTomcatWebServerFactory factory) { ConfigurableTomcatWebServerFactory factory) {
AccessLogValve valve = new AccessLogValve(); AccessLogValve valve = new AccessLogValve();
valve.setPattern(tomcatProperties.getAccesslog().getPattern()); valve.setPattern(tomcatProperties.getAccesslog().getPattern());
valve.setDirectory(tomcatProperties.getAccesslog().getDirectory()); valve.setDirectory(tomcatProperties.getAccesslog().getDirectory());

@ -38,7 +38,6 @@ public final class UndertowCustomizer {
public static void customizeUndertow(ServerProperties serverProperties, public static void customizeUndertow(ServerProperties serverProperties,
Environment environment, ConfigurableUndertowWebServerFactory factory) { Environment environment, ConfigurableUndertowWebServerFactory factory) {
ServerProperties.Undertow undertowProperties = serverProperties.getUndertow(); ServerProperties.Undertow undertowProperties = serverProperties.getUndertow();
ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties ServerProperties.Undertow.Accesslog accesslogProperties = undertowProperties
.getAccesslog(); .getAccesslog();

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -327,6 +327,7 @@ public class WebMvcProperties {
public void setParameterName(String parameterName) { public void setParameterName(String parameterName) {
this.parameterName = parameterName; this.parameterName = parameterName;
} }
} }
public static class PathMatch { public static class PathMatch {
@ -360,6 +361,7 @@ public class WebMvcProperties {
public void setUseRegisteredSuffixPattern(boolean useRegisteredSuffixPattern) { public void setUseRegisteredSuffixPattern(boolean useRegisteredSuffixPattern) {
this.useRegisteredSuffixPattern = useRegisteredSuffixPattern; this.useRegisteredSuffixPattern = useRegisteredSuffixPattern;
} }
} }
public enum LocaleResolver { public enum LocaleResolver {

@ -238,22 +238,21 @@ public class ErrorMvcAutoConfiguration {
if (response.getContentType() == null) { if (response.getContentType() == null) {
response.setContentType(getContentType()); response.setContentType(getContentType());
} }
PlaceholderResolver resolver = new ExpressionResolver(getExpressions(), model); PlaceholderResolver resolver = new ExpressionResolver(getExpressions(),
model);
String result = this.helper.replacePlaceholders(this.template, resolver); String result = this.helper.replacePlaceholders(this.template, resolver);
response.getWriter().append(result); response.getWriter().append(result);
} }
private String getMessage(Map<String, ?> model) { private String getMessage(Map<String, ?> model) {
StringBuilder builder = new StringBuilder(); Object path = model.get("path");
builder.append("Cannot render error page for request [") String message = "Cannot render error page for request [" + path + "]";
.append(model.get("path")).append("]");
if (model.get("message") != null) { if (model.get("message") != null) {
builder.append(" and exception [").append(model.get("message")) message += " and exception [" + model.get("message") + "]";
.append("]");
} }
return builder.append("] as the response has already been committed.") message += " as the response has already been committed.";
.append("As a result, the response may have the wrong status code.") message += " As a result, the response may have the wrong status code.";
.toString(); return message;
} }
private Map<String, Expression> getExpressions() { private Map<String, Expression> getExpressions() {

@ -25,12 +25,11 @@ import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.boot.web.servlet.error.ErrorAttributes; import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.servlet.View; import org.springframework.web.servlet.View;
import org.springframework.web.servlet.handler.DispatcherServletWebRequest; import org.springframework.web.servlet.handler.DispatcherServletWebRequest;
import static org.hamcrest.Matchers.allOf; import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
/** /**
* Tests for {@link ErrorMvcAutoConfiguration}. * Tests for {@link ErrorMvcAutoConfiguration}.
@ -50,26 +49,31 @@ public class ErrorMvcAutoConfigurationTests {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
View errorView = context.getBean("error", View.class); View errorView = context.getBean("error", View.class);
ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class); ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);
DispatcherServletWebRequest webRequest = DispatcherServletWebRequest webRequest = createCommittedWebRequest(
createCommittedWebRequest(new IllegalStateException("Exception message")); new IllegalStateException("Exception message"));
errorView.render(errorAttributes.getErrorAttributes(webRequest, true), errorView.render(errorAttributes.getErrorAttributes(webRequest, true),
webRequest.getRequest(), webRequest.getResponse()); webRequest.getRequest(), webRequest.getResponse());
this.outputCapture.expect(allOf( assertThat(this.outputCapture.toString())
containsString("Cannot render error page for request [/path]" + .contains("Cannot render error page for request [/path] "
" and exception [Exception message]] as the response has already been committed."), + "and exception [Exception message] as the response has "
containsString("As a result, the response may have the wrong status code."))); + "already been committed. As a result, the response may "
+ "have the wrong status code.");
}); });
} }
protected DispatcherServletWebRequest createCommittedWebRequest(Exception e) { protected DispatcherServletWebRequest createCommittedWebRequest(Exception ex) {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response); DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request,
webRequest.setAttribute("javax.servlet.error.exception", e, WebRequest.SCOPE_REQUEST); response);
webRequest.setAttribute("javax.servlet.error.request_uri", "/path", WebRequest.SCOPE_REQUEST); webRequest.setAttribute("javax.servlet.error.exception", ex,
RequestAttributes.SCOPE_REQUEST);
webRequest.setAttribute("javax.servlet.error.request_uri", "/path",
RequestAttributes.SCOPE_REQUEST);
response.setCommitted(true); response.setCommitted(true);
response.setOutputStreamAccessAllowed(false); response.setOutputStreamAccessAllowed(false);
response.setWriterAccessAllowed(false); response.setWriterAccessAllowed(false);
return webRequest; return webRequest;
} }
} }

@ -36,6 +36,8 @@ import java.util.TreeSet;
*/ */
class ServiceCapabilitiesReportGenerator { class ServiceCapabilitiesReportGenerator {
private static final String NEW_LINE = System.lineSeparator();
private final InitializrService initializrService; private final InitializrService initializrService;
/** /**
@ -64,29 +66,29 @@ class ServiceCapabilitiesReportGenerator {
private String generateHelp(String url, InitializrServiceMetadata metadata) { private String generateHelp(String url, InitializrServiceMetadata metadata) {
String header = "Capabilities of " + url; String header = "Capabilities of " + url;
StringBuilder report = new StringBuilder(); StringBuilder report = new StringBuilder();
report.append(repeat("=", header.length()) + System.lineSeparator()); report.append(repeat("=", header.length()) + NEW_LINE);
report.append(header + System.lineSeparator()); report.append(header + NEW_LINE);
report.append(repeat("=", header.length()) + System.lineSeparator()); report.append(repeat("=", header.length()) + NEW_LINE);
report.append(System.lineSeparator()); report.append(NEW_LINE);
reportAvailableDependencies(metadata, report); reportAvailableDependencies(metadata, report);
report.append(System.lineSeparator()); report.append(NEW_LINE);
reportAvailableProjectTypes(metadata, report); reportAvailableProjectTypes(metadata, report);
report.append(System.lineSeparator()); report.append(NEW_LINE);
reportDefaults(report, metadata); reportDefaults(report, metadata);
return report.toString(); return report.toString();
} }
private void reportAvailableDependencies(InitializrServiceMetadata metadata, private void reportAvailableDependencies(InitializrServiceMetadata metadata,
StringBuilder report) { StringBuilder report) {
report.append("Available dependencies:" + System.lineSeparator()); report.append("Available dependencies:" + NEW_LINE);
report.append("-----------------------" + System.lineSeparator()); report.append("-----------------------" + NEW_LINE);
List<Dependency> dependencies = getSortedDependencies(metadata); List<Dependency> dependencies = getSortedDependencies(metadata);
for (Dependency dependency : dependencies) { for (Dependency dependency : dependencies) {
report.append(dependency.getId() + " - " + dependency.getName()); report.append(dependency.getId() + " - " + dependency.getName());
if (dependency.getDescription() != null) { if (dependency.getDescription() != null) {
report.append(": " + dependency.getDescription()); report.append(": " + dependency.getDescription());
} }
report.append(System.lineSeparator()); report.append(NEW_LINE);
} }
} }
@ -98,8 +100,8 @@ class ServiceCapabilitiesReportGenerator {
private void reportAvailableProjectTypes(InitializrServiceMetadata metadata, private void reportAvailableProjectTypes(InitializrServiceMetadata metadata,
StringBuilder report) { StringBuilder report) {
report.append("Available project types:" + System.lineSeparator()); report.append("Available project types:" + NEW_LINE);
report.append("------------------------" + System.lineSeparator()); report.append("------------------------" + NEW_LINE);
SortedSet<Entry<String, ProjectType>> entries = new TreeSet<>( SortedSet<Entry<String, ProjectType>> entries = new TreeSet<>(
Comparator.comparing(Entry::getKey)); Comparator.comparing(Entry::getKey));
entries.addAll(metadata.getProjectTypes().entrySet()); entries.addAll(metadata.getProjectTypes().entrySet());
@ -112,7 +114,7 @@ class ServiceCapabilitiesReportGenerator {
if (type.isDefaultType()) { if (type.isDefaultType()) {
report.append(" (default)"); report.append(" (default)");
} }
report.append(System.lineSeparator()); report.append(NEW_LINE);
} }
} }
@ -132,13 +134,13 @@ class ServiceCapabilitiesReportGenerator {
private void reportDefaults(StringBuilder report, private void reportDefaults(StringBuilder report,
InitializrServiceMetadata metadata) { InitializrServiceMetadata metadata) {
report.append("Defaults:" + System.lineSeparator()); report.append("Defaults:" + NEW_LINE);
report.append("---------" + System.lineSeparator()); report.append("---------" + NEW_LINE);
List<String> defaultsKeys = new ArrayList<>(metadata.getDefaults().keySet()); List<String> defaultsKeys = new ArrayList<>(metadata.getDefaults().keySet());
Collections.sort(defaultsKeys); Collections.sort(defaultsKeys);
for (String defaultsKey : defaultsKeys) { for (String defaultsKey : defaultsKeys) {
String defaultsValue = metadata.getDefaults().get(defaultsKey); String defaultsValue = metadata.getDefaults().get(defaultsKey);
report.append(defaultsKey + ": " + defaultsValue + System.lineSeparator()); report.append(defaultsKey + ": " + defaultsValue + NEW_LINE);
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -2939,8 +2939,10 @@ for the properties of the user).
* Form-based login or HTTP Basic security (depending on Content-Type) for the entire * Form-based login or HTTP Basic security (depending on Content-Type) for the entire
application (including actuator endpoints if actuator is on the classpath). application (including actuator endpoints if actuator is on the classpath).
== MVC Security
[[boot-features-security-mvc]]
== MVC Security
The default security configuration is implemented in `SecurityAutoConfiguration` and in The default security configuration is implemented in `SecurityAutoConfiguration` and in
the classes imported from there (`SpringBootWebSecurityConfiguration` for web security the classes imported from there (`SpringBootWebSecurityConfiguration` for web security
and `AuthenticationManagerConfiguration` for authentication configuration, which is also and `AuthenticationManagerConfiguration` for authentication configuration, which is also
@ -2960,8 +2962,10 @@ that is based on the `management.endpoints.web.base-path` property.
`StaticResourceRequest` can be used to create a `RequestMatcher` for static resources in `StaticResourceRequest` can be used to create a `RequestMatcher` for static resources in
commonly used locations. commonly used locations.
== WebFlux Security
[[boot-features-security-webflux]]
== WebFlux Security
The default security configuration is implemented in `ReactiveSecurityAutoConfiguration` and in The default security configuration is implemented in `ReactiveSecurityAutoConfiguration` and in
the classes imported from there (`WebFluxSecurityConfiguration` for web security the classes imported from there (`WebFluxSecurityConfiguration` for web security
and `ReactiveAuthenticationManagerConfiguration` for authentication configuration, which is also and `ReactiveAuthenticationManagerConfiguration` for authentication configuration, which is also
@ -2977,12 +2981,15 @@ Boot provides convenience methods that can be used to override access rules for
endpoints and static resources. `EndpointRequest` can be used to create a `ServerWebExchangeMatcher` endpoints and static resources. `EndpointRequest` can be used to create a `ServerWebExchangeMatcher`
that is based on the `management.endpoints.web.base-path` property. that is based on the `management.endpoints.web.base-path` property.
[[boot-features-security-oauth2]] [[boot-features-security-oauth2]]
=== OAuth2 === OAuth2
https://oauth.net/2/[OAuth2] is a widely used authorization framework that is supported by https://oauth.net/2/[OAuth2] is a widely used authorization framework that is supported by
Spring. Spring.
[[boot-features-security-oauth2-client]]
==== Client ==== Client
If you have `spring-security-oauth2-client` on your classpath, you can take advantage of If you have `spring-security-oauth2-client` on your classpath, you can take advantage of
some auto-configuration to make it easy to set up an OAuth2 Client. This configuration some auto-configuration to make it easy to set up an OAuth2 Client. This configuration

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -27,6 +27,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
public class DescriptionExtractorTests { public class DescriptionExtractorTests {
private static final String NEW_LINE = System.lineSeparator();
private DescriptionExtractor extractor = new DescriptionExtractor(); private DescriptionExtractor extractor = new DescriptionExtractor();
@Test @Test
@ -39,16 +41,14 @@ public class DescriptionExtractorTests {
@Test @Test
public void extractShortDescriptionNewLineBeforeDot() { public void extractShortDescriptionNewLineBeforeDot() {
String description = this.extractor.getShortDescription( String description = this.extractor.getShortDescription(
"My short" + System.lineSeparator() + "description." "My short" + NEW_LINE + "description." + NEW_LINE + "More stuff.");
+ System.lineSeparator() + "More stuff.");
assertThat(description).isEqualTo("My short description."); assertThat(description).isEqualTo("My short description.");
} }
@Test @Test
public void extractShortDescriptionNewLineBeforeDotWithSpaces() { public void extractShortDescriptionNewLineBeforeDotWithSpaces() {
String description = this.extractor.getShortDescription( String description = this.extractor.getShortDescription(
"My short " + System.lineSeparator() + " description. " "My short " + NEW_LINE + " description. " + NEW_LINE + "More stuff.");
+ System.lineSeparator() + "More stuff.");
assertThat(description).isEqualTo("My short description."); assertThat(description).isEqualTo("My short description.");
} }
@ -61,8 +61,7 @@ public class DescriptionExtractorTests {
@Test @Test
public void extractShortDescriptionNoDotMultipleLines() { public void extractShortDescriptionNoDotMultipleLines() {
String description = this.extractor String description = this.extractor
.getShortDescription("My short description " + System.lineSeparator() .getShortDescription("My short description " + NEW_LINE + " More stuff");
+ " More stuff");
assertThat(description).isEqualTo("My short description"); assertThat(description).isEqualTo("My short description");
} }

@ -21,8 +21,8 @@ import javax.validation.constraints.NotEmpty;
import org.springframework.boot.configurationsample.ConfigurationProperties; import org.springframework.boot.configurationsample.ConfigurationProperties;
/** /**
* An annotated getter with {@code NotEmpty} that triggers a different class type * An annotated getter with {@code NotEmpty} that triggers a different class type in the
* in the compiler. See #11512 * compiler. See #11512
* *
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -85,9 +85,7 @@ public abstract class ApplicationContextServerWebExchangeMatcher<C>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private C createContext(ServerWebExchange exchange) { private C createContext(ServerWebExchange exchange) {
ApplicationContext context = exchange.getApplicationContext(); ApplicationContext context = exchange.getApplicationContext();
if (context == null) { Assert.state(context != null, "No WebApplicationContext found.");
throw new IllegalStateException("No WebApplicationContext found.");
}
if (this.contextClass.isInstance(context)) { if (this.contextClass.isInstance(context)) {
return (C) context; return (C) context;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -24,6 +24,7 @@ import org.eclipse.jetty.server.Server;
/** /**
* {@link JettyServerCustomizer} to add {@link ForwardedRequestCustomizer}. * {@link JettyServerCustomizer} to add {@link ForwardedRequestCustomizer}.
*
* @author Phillip Webb * @author Phillip Webb
*/ */
class ForwardHeadersCustomizer implements JettyServerCustomizer { class ForwardHeadersCustomizer implements JettyServerCustomizer {

@ -234,8 +234,7 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
SessionHandler handler = context.getSessionHandler(); SessionHandler handler = context.getSessionHandler();
Duration sessionTimeout = getSession().getTimeout(); Duration sessionTimeout = getSession().getTimeout();
handler.setMaxInactiveInterval( handler.setMaxInactiveInterval(
(sessionTimeout == null || sessionTimeout.isNegative()) ? -1 isNegative(sessionTimeout) ? -1 : (int) sessionTimeout.getSeconds());
: (int) sessionTimeout.getSeconds());
if (getSession().isPersistent()) { if (getSession().isPersistent()) {
DefaultSessionCache cache = new DefaultSessionCache(handler); DefaultSessionCache cache = new DefaultSessionCache(handler);
FileSessionDataStore store = new FileSessionDataStore(); FileSessionDataStore store = new FileSessionDataStore();
@ -245,6 +244,10 @@ public class JettyServletWebServerFactory extends AbstractServletWebServerFactor
} }
} }
private boolean isNegative(Duration sessionTimeout) {
return sessionTimeout == null || sessionTimeout.isNegative();
}
private void addLocaleMappings(WebAppContext context) { private void addLocaleMappings(WebAppContext context) {
for (Map.Entry<Locale, Charset> entry : getLocaleCharsetMappings().entrySet()) { for (Map.Entry<Locale, Charset> entry : getLocaleCharsetMappings().entrySet()) {
Locale locale = entry.getKey(); Locale locale = entry.getKey();

@ -135,4 +135,5 @@ public class SslServerCustomizer implements NettyServerCustomizer {
store.load(url.openStream(), password == null ? null : password.toCharArray()); store.load(url.openStream(), password == null ? null : password.toCharArray());
return store; return store;
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -386,13 +386,17 @@ public class TomcatServletWebServerFactory extends AbstractServletWebServerFacto
private long getSessionTimeoutInMinutes() { private long getSessionTimeoutInMinutes() {
Duration sessionTimeout = getSession().getTimeout(); Duration sessionTimeout = getSession().getTimeout();
if (sessionTimeout == null || sessionTimeout.isNegative() if (isZeroOrLess(sessionTimeout)) {
|| sessionTimeout.isZero()) {
return 0; return 0;
} }
return Math.max(sessionTimeout.toMinutes(), 1); return Math.max(sessionTimeout.toMinutes(), 1);
} }
private boolean isZeroOrLess(Duration sessionTimeout) {
return sessionTimeout == null || sessionTimeout.isNegative()
|| sessionTimeout.isZero();
}
/** /**
* Post process the Tomcat {@link Context} before it's used with the Tomcat Server. * Post process the Tomcat {@link Context} before it's used with the Tomcat Server.
* Subclasses can override this method to apply additional processing to the * Subclasses can override this method to apply additional processing to the

@ -283,13 +283,17 @@ public class UndertowServletWebServerFactory extends AbstractServletWebServerFac
manager.deploy(); manager.deploy();
SessionManager sessionManager = manager.getDeployment().getSessionManager(); SessionManager sessionManager = manager.getDeployment().getSessionManager();
Duration timeoutDuration = getSession().getTimeout(); Duration timeoutDuration = getSession().getTimeout();
int sessionTimeout = (timeoutDuration == null || timeoutDuration.isZero() int sessionTimeout = (isZeroOrLess(timeoutDuration) ? -1
|| timeoutDuration.isNegative() ? -1 : (int) timeoutDuration.getSeconds());
: (int) timeoutDuration.getSeconds());
sessionManager.setDefaultSessionTimeout(sessionTimeout); sessionManager.setDefaultSessionTimeout(sessionTimeout);
return manager; return manager;
} }
private boolean isZeroOrLess(Duration timeoutDuration) {
return timeoutDuration == null || timeoutDuration.isZero()
|| timeoutDuration.isNegative();
}
private void configureAccessLog(DeploymentInfo deploymentInfo) { private void configureAccessLog(DeploymentInfo deploymentInfo) {
deploymentInfo.addInitialHandlerChainWrapper(this::createAccessLogHandler); deploymentInfo.addInitialHandlerChainWrapper(this::createAccessLogHandler);
} }

@ -62,31 +62,10 @@ public interface ConfigurableServletWebServerFactory
/** /**
* Sets the configuration that will be applied to the container's HTTP session * Sets the configuration that will be applied to the container's HTTP session
* support. * support.
*
* @param session the session configuration * @param session the session configuration
*/ */
void setSession(Session session); void setSession(Session session);
// /**
// * The session timeout in seconds (default 30 minutes). If {@code null} then
// sessions
// * never expire.
// * @param sessionTimeout the session timeout
// */
// void setSessionTimeout(Duration sessionTimeout);
//
// /**
// * Sets if session data should be persisted between restarts.
// * @param persistSession {@code true} if session data should be persisted
// */
// void setPersistSession(boolean persistSession);
//
// /**
// * Set the directory used to store serialized session data.
// * @param sessionStoreDir the directory or {@code null} to use a default location.
// */
// void setSessionStoreDir(File sessionStoreDir);
/** /**
* Set if the DefaultServlet should be registered. Defaults to {@code true} so that * Set if the DefaultServlet should be registered. Defaults to {@code true} so that
* files from the {@link #setDocumentRoot(File) document root} will be served. * files from the {@link #setDocumentRoot(File) document root} will be served.
@ -141,7 +120,6 @@ public interface ConfigurableServletWebServerFactory
/** /**
* Sets the init parameters that are applied to the container's * Sets the init parameters that are applied to the container's
* {@link ServletContext}. * {@link ServletContext}.
*
* @param initParameters the init parameters * @param initParameters the init parameters
*/ */
void setInitParameters(Map<String, String> initParameters); void setInitParameters(Map<String, String> initParameters);

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -156,7 +156,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ssl.setKeyStore("classpath:test.jks"); ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password"); ssl.setKeyPassword("password");
ssl.setTrustStore("classpath:test.jks"); ssl.setTrustStore("classpath:test.jks");
testClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector()); testClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector());
} }
@ -168,7 +167,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ssl.setKeyStore("classpath:test.jks"); ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password"); ssl.setKeyPassword("password");
ssl.setTrustStore("classpath:test.jks"); ssl.setTrustStore("classpath:test.jks");
testClientAuthSuccess(ssl, buildTrustAllSslConnector()); testClientAuthSuccess(ssl, buildTrustAllSslConnector());
} }
@ -192,10 +190,8 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ReactorClientHttpConnector clientConnector) { ReactorClientHttpConnector clientConnector) {
AbstractReactiveWebServerFactory factory = getFactory(); AbstractReactiveWebServerFactory factory = getFactory();
factory.setSsl(sslConfiguration); factory.setSsl(sslConfiguration);
this.webServer = factory.getWebServer(new EchoHandler()); this.webServer = factory.getWebServer(new EchoHandler());
this.webServer.start(); this.webServer.start();
WebClient client = WebClient.builder() WebClient client = WebClient.builder()
.baseUrl("https://localhost:" + this.webServer.getPort()) .baseUrl("https://localhost:" + this.webServer.getPort())
.clientConnector(clientConnector).build(); .clientConnector(clientConnector).build();
@ -213,7 +209,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ssl.setKeyStore("classpath:test.jks"); ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password"); ssl.setKeyPassword("password");
ssl.setTrustStore("classpath:test.jks"); ssl.setTrustStore("classpath:test.jks");
testClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector()); testClientAuthSuccess(ssl, buildTrustAllSslWithClientKeyConnector());
} }
@ -228,7 +223,6 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ssl.setKeyStore("classpath:test.jks"); ssl.setKeyStore("classpath:test.jks");
ssl.setKeyPassword("password"); ssl.setKeyPassword("password");
ssl.setTrustStore("classpath:test.jks"); ssl.setTrustStore("classpath:test.jks");
testClientAuthFailure(ssl, buildTrustAllSslConnector()); testClientAuthFailure(ssl, buildTrustAllSslConnector());
} }
@ -236,17 +230,14 @@ public abstract class AbstractReactiveWebServerFactoryTests {
ReactorClientHttpConnector clientConnector) { ReactorClientHttpConnector clientConnector) {
AbstractReactiveWebServerFactory factory = getFactory(); AbstractReactiveWebServerFactory factory = getFactory();
factory.setSsl(sslConfiguration); factory.setSsl(sslConfiguration);
this.webServer = factory.getWebServer(new EchoHandler()); this.webServer = factory.getWebServer(new EchoHandler());
this.webServer.start(); this.webServer.start();
WebClient client = WebClient.builder() WebClient client = WebClient.builder()
.baseUrl("https://localhost:" + this.webServer.getPort()) .baseUrl("https://localhost:" + this.webServer.getPort())
.clientConnector(clientConnector).build(); .clientConnector(clientConnector).build();
Mono<String> result = client.post().uri("/test").contentType(MediaType.TEXT_PLAIN) Mono<String> result = client.post().uri("/test").contentType(MediaType.TEXT_PLAIN)
.body(BodyInserters.fromObject("Hello World")).exchange() .body(BodyInserters.fromObject("Hello World")).exchange()
.flatMap((response) -> response.bodyToMono(String.class)); .flatMap((response) -> response.bodyToMono(String.class));
StepVerifier.create(result).expectError(SSLException.class) StepVerifier.create(result).expectError(SSLException.class)
.verify(Duration.ofSeconds(10)); .verify(Duration.ofSeconds(10));
} }
@ -372,6 +363,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
} }
ctx.fireChannelRead(msg); ctx.fireChannelRead(msg);
} }
} }
protected static class CharsHandler implements HttpHandler { protected static class CharsHandler implements HttpHandler {
@ -395,6 +387,7 @@ public abstract class AbstractReactiveWebServerFactoryTests {
response.getHeaders().setContentType(this.mediaType); response.getHeaders().setContentType(this.mediaType);
return response.writeWith(Mono.just(this.bytes)); return response.writeWith(Mono.just(this.bytes));
} }
} }
} }

@ -999,15 +999,6 @@ public abstract class AbstractServletWebServerFactoryTests {
@Test @Test
public void sessionConfiguration() { public void sessionConfiguration() {
AbstractServletWebServerFactory factory = getFactory(); AbstractServletWebServerFactory factory = getFactory();
// map.put("server.servlet.session.timeout", "123");
// map.put("server.servlet.session.tracking-modes", "cookie,url");
// map.put("server.servlet.session.cookie.name", "testname");
// map.put("server.servlet.session.cookie.domain", "testdomain");
// map.put("server.servlet.session.cookie.path", "/testpath");
// map.put("server.servlet.session.cookie.comment", "testcomment");
// map.put("server.servlet.session.cookie.http-only", "true");
// map.put("server.servlet.session.cookie.secure", "true");
// map.put("server.servlet.session.cookie.max-age", "60");
factory.getSession().setTimeout(Duration.ofSeconds(123)); factory.getSession().setTimeout(Duration.ofSeconds(123));
factory.getSession().setTrackingModes( factory.getSession().setTrackingModes(
EnumSet.of(SessionTrackingMode.COOKIE, SessionTrackingMode.URL)); EnumSet.of(SessionTrackingMode.COOKIE, SessionTrackingMode.URL));
@ -1035,7 +1026,6 @@ public abstract class AbstractServletWebServerFactoryTests {
assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue(); assertThat(servletContext.getSessionCookieConfig().isHttpOnly()).isTrue();
assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue(); assertThat(servletContext.getSessionCookieConfig().isSecure()).isTrue();
assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60); assertThat(servletContext.getSessionCookieConfig().getMaxAge()).isEqualTo(60);
} }
protected abstract void addConnector(int port, protected abstract void addConnector(int port,

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -41,7 +41,8 @@ import org.springframework.test.web.reactive.server.WebTestClient;
* @author Madhura Bhave * @author Madhura Bhave
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { SampleSecureWebFluxCustomSecurityTests.SecurityConfiguration.class, @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {
SampleSecureWebFluxCustomSecurityTests.SecurityConfiguration.class,
SampleSecureWebFluxApplication.class }) SampleSecureWebFluxApplication.class })
public class SampleSecureWebFluxCustomSecurityTests { public class SampleSecureWebFluxCustomSecurityTests {
@ -82,22 +83,18 @@ public class SampleSecureWebFluxCustomSecurityTests {
@Bean @Bean
public MapReactiveUserDetailsService userDetailsService() { public MapReactiveUserDetailsService userDetailsService() {
return new MapReactiveUserDetailsService( return new MapReactiveUserDetailsService(
User.withDefaultPasswordEncoder().username("user").password("password") User.withDefaultPasswordEncoder().username("user")
.authorities("ROLE_USER").build(), .password("password").authorities("ROLE_USER").build(),
User.withDefaultPasswordEncoder().username("admin").password("admin") User.withDefaultPasswordEncoder().username("admin").password("admin")
.authorities("ROLE_ACTUATOR", "ROLE_USER").build()); .authorities("ROLE_ACTUATOR", "ROLE_USER").build());
} }
@Bean @Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http http.authorizeExchange().matchers(EndpointRequest.to("health", "info"))
.authorizeExchange() .permitAll().matchers(EndpointRequest.toAnyEndpoint())
.matchers(EndpointRequest.to("health", "info")).permitAll() .hasRole("ACTUATOR").pathMatchers("/login").permitAll().anyExchange()
.matchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR") .authenticated().and().httpBasic();
.pathMatchers("/login").permitAll()
.anyExchange().authenticated()
.and()
.httpBasic();
return http.build(); return http.build();
} }
@ -112,4 +109,3 @@ public class SampleSecureWebFluxCustomSecurityTests {
} }
} }

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2017 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

Loading…
Cancel
Save