Merge branch '1.4.x' into 1.5.x

This commit is contained in:
Phillip Webb 2016-11-03 14:49:38 -07:00
commit 81c5753f4d
12 changed files with 281 additions and 19 deletions

View File

@ -20,6 +20,7 @@ import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpSession;
import javax.validation.constraints.NotNull;
import org.springframework.boot.autoconfigure.security.SecurityPrerequisite;
@ -28,8 +29,6 @@ import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.embedded.Ssl;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
@ -43,8 +42,6 @@ import org.springframework.util.StringUtils;
@ConfigurationProperties(prefix = "management", ignoreUnknownFields = true)
public class ManagementServerProperties implements SecurityPrerequisite {
private static final String SECURITY_CHECK_CLASS = "org.springframework.security.config.http.SessionCreationPolicy";
/**
* Order applied to the WebSecurityConfigurerAdapter that is used to configure basic
* authentication for management endpoints. If you want to add your own authentication
@ -89,14 +86,7 @@ public class ManagementServerProperties implements SecurityPrerequisite {
*/
private boolean addApplicationContextHeader = true;
private final Security security = maybeCreateSecurity();
private Security maybeCreateSecurity() {
if (ClassUtils.isPresent(SECURITY_CHECK_CLASS, null)) {
return new Security();
}
return null;
}
private final Security security = new Security();
/**
* Returns the management port or {@code null} if the
@ -181,7 +171,8 @@ public class ManagementServerProperties implements SecurityPrerequisite {
private List<String> roles = Arrays.asList("ADMIN");
/**
* Session creating policy to use (always, never, if_required, stateless).
* Session creating policy for security use (always, never, if_required,
* stateless).
*/
private SessionCreationPolicy sessions = SessionCreationPolicy.STATELESS;
@ -211,4 +202,29 @@ public class ManagementServerProperties implements SecurityPrerequisite {
}
public enum SessionCreationPolicy {
/**
* Always create an {@link HttpSession}.
*/
ALWAYS,
/**
* Never create an {@link HttpSession}, but use any {@link HttpSession} that
* already exists.
*/
NEVER,
/**
* Only create an {@link HttpSession} if required.
*/
IF_REQUIRED,
/**
* Never create an {@link HttpSession}.
*/
STATELESS
}
}

View File

@ -64,6 +64,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -274,13 +275,22 @@ public class ManagementWebSecurityAutoConfiguration {
http.httpBasic().authenticationEntryPoint(entryPoint);
// No cookies for management endpoints by default
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(
this.management.getSecurity().getSessions());
http.sessionManagement()
.sessionCreationPolicy(asSpringSecuritySessionCreationPolicy(
this.management.getSecurity().getSessions()));
SpringBootWebSecurityConfiguration.configureHeaders(http.headers(),
this.security.getHeaders());
}
}
private SessionCreationPolicy asSpringSecuritySessionCreationPolicy(
Enum<?> value) {
if (value == null) {
return SessionCreationPolicy.STATELESS;
}
return SessionCreationPolicy.valueOf(value.name());
}
private RequestMatcher getRequestMatcher() {
if (this.management.getSecurity().isEnabled()) {
return LazyEndpointPathRequestMatcher

View File

@ -218,8 +218,8 @@ class NoSuchBeanDefinitionFailureAnalyzer
}
String name = cause.getBeanName();
ResolvableType resolvableType = cause.getResolvableType();
return ((name != null && hasName(candidate, name))
|| (resolvableType != null && hasType(candidate, extractBeanType(resolvableType))));
return ((name != null && hasName(candidate, name)) || (resolvableType != null
&& hasType(candidate, extractBeanType(resolvableType))));
}
private boolean hasName(MethodMetadata methodMetadata, String name) {

View File

@ -87,8 +87,8 @@ public class NoSuchBeanDefinitionFailureAnalyzerTests {
public void failureAnalysisForMissingCollectionType() throws Exception {
FailureAnalysis analysis = analyzeFailure(
createFailure(StringCollectionConfiguration.class));
assertDescriptionConstructorMissingType(analysis, StringCollectionHandler.class, 0,
String.class);
assertDescriptionConstructorMissingType(analysis, StringCollectionHandler.class,
0, String.class);
assertBeanMethodDisabled(analysis,
"did not find property 'spring.string.enabled'",
TestPropertyAutoConfiguration.class, "string");

View File

@ -25,6 +25,7 @@
<module>spring-boot-sample-activemq</module>
<module>spring-boot-sample-actuator</module>
<module>spring-boot-sample-actuator-log4j2</module>
<module>spring-boot-sample-actuator-no-security</module>
<module>spring-boot-sample-actuator-noweb</module>
<module>spring-boot-sample-actuator-ui</module>
<module>spring-boot-sample-amqp</module>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<!-- Your own application should inherit from spring-boot-starter-parent -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-samples</artifactId>
<version>1.4.2.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-actuator-no-security</artifactId>
<name>Spring Boot Actuator UI Sample</name>
<description>Spring Boot Actuator UI Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,49 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.actuator.nosecurity;
import java.util.Date;
import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@SpringBootApplication
@Controller
public class SampleActuatorNoSecurityApplication {
@GetMapping("/")
public String home(Map<String, Object> model) {
model.put("message", "Hello World");
model.put("title", "Hello Home");
model.put("date", new Date());
return "home";
}
@RequestMapping("/foo")
public String foo() {
throw new RuntimeException("Expected exception in controller");
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleActuatorNoSecurityApplication.class, args);
}
}

View File

@ -0,0 +1,2 @@
health.diskspace.enabled=false
management.security.role=superuser

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,32 @@
<#import "/spring.ftl" as spring />
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<#assign home><@spring.url relativeUrl="/"/></#assign>
<#assign bootstrap><@spring.url relativeUrl="/css/bootstrap.min.css"/></#assign>
<link rel="stylesheet" href="${bootstrap}" />
</head>
<body>
<div class="container">
<div class="navbar">
<div class="navbar-inner">
<a class="brand" href="http://freemarker.org/"> FreeMarker -
Plain </a>
<ul class="nav">
<li><a href="${home}"> Home </a></li>
</ul>
</div>
</div>
<h1>Error Page</h1>
<div id="created">${timestamp?datetime}</div>
<div>
There was an unexpected error (type=${error}, status=${status}).
</div>
<div>${message}</div>
<div>
Please contact the operator with the above information.
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<#import "/spring.ftl" as spring />
<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
<#assign home><@spring.url relativeUrl="/"/></#assign>
<#assign bootstrap><@spring.url relativeUrl="/css/bootstrap.min.css"/></#assign>
<link rel="stylesheet" href="${bootstrap}" />
</head>
<body>
<div class="container">
<div class="navbar">
<div class="navbar-inner">
<a class="brand" href="http://freemarker.org/"> FreeMarker -
Plain </a>
<ul class="nav">
<li><a href="${home}"> Home </a></li>
</ul>
</div>
</div>
<h1>${title}</h1>
<div>${message}</div>
<div id="created">${date?datetime}</div>
</div>
</body>
</html>

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.actuator.nosecurity;
import java.util.Arrays;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Basic integration tests for demo application.
*
* @author Phillip Webb
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class SampleActuatorNoSecurityApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testHome() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET,
new HttpEntity<Void>(headers), String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("<title>Hello");
}
@Test
public void testMetrics() throws Exception {
@SuppressWarnings("rawtypes")
ResponseEntity<Map> entity = this.restTemplate.getForEntity("/metrics",
Map.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}