Skip to content

Commit d455810

Browse files
committed
Report section for Actuator Endpoints Sanitization
- Report section rendered for Boot 2.7 and 3.0
1 parent c57596c commit d455810

File tree

5 files changed

+322
-16
lines changed

5 files changed

+322
-16
lines changed

components/sbm-recipes-boot-upgrade/src/main/java/org/springframework/sbm/boot/upgrade_27_30/report/SpringBootUpgradeReportSection.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,10 @@ public List<Author> getAuthors() {
245245

246246
private String renderRemediation() {
247247
StringBuilder sb = new StringBuilder();
248-
sb.append(remediation.getDescription()).append(ls).append(ls);
248+
if(remediation.getDescription() != null) {
249+
sb.append(remediation.getDescription()).append(ls);
250+
}
251+
sb.append(ls);
249252
if(remediation.getPossibilities().isEmpty()) {
250253
renderResourcesList(sb, remediation);
251254
renderRecipeButton(sb, remediation.getRecipe());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2021 - 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.sbm.boot.upgrade_27_30.report.helper;
17+
import org.springframework.sbm.boot.common.conditions.IsSpringBootProject;
18+
import org.springframework.sbm.boot.upgrade_27_30.report.SpringBootUpgradeReportSection;
19+
import org.springframework.sbm.build.api.BuildFile;
20+
import org.springframework.sbm.build.api.Module;
21+
import org.springframework.sbm.engine.context.ProjectContext;
22+
import org.springframework.sbm.project.resource.ProjectResource;
23+
24+
import java.util.Comparator;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.stream.Collectors;
28+
29+
/**
30+
* @author Fabian Krüger
31+
*/
32+
public class ActuatorEndpointsSanitizationHelper extends SpringBootUpgradeReportSection.AbstractHelper<List<BuildFile>> {
33+
34+
private static final String ACTUATOR_GROUP_ID = "org.springframework.boot";
35+
private static final String ACTUATOR_ARTIFACT_ID = "spring-boot-actuator";
36+
public static final String VERSION_PATTERN = "(2\\.7\\..*)|(3\\.0\\..*)";
37+
private List<BuildFile> buildFilesWithActuatorOnClasspath;
38+
39+
@Override
40+
public boolean evaluate(ProjectContext context) {
41+
IsSpringBootProject isSpringBootProjectCondition = new IsSpringBootProject();
42+
isSpringBootProjectCondition.setVersionPattern(VERSION_PATTERN);
43+
boolean isSpringBoot3Application = isSpringBootProjectCondition.evaluate(context);
44+
if(! isSpringBoot3Application) {
45+
return false;
46+
}
47+
buildFilesWithActuatorOnClasspath = getActuatorDependency(context);
48+
return ! buildFilesWithActuatorOnClasspath.isEmpty();
49+
}
50+
51+
private List<BuildFile> getActuatorDependency(ProjectContext context) {
52+
return context.getApplicationModules().stream()
53+
.map(Module::getBuildFile)
54+
.filter(b -> b.getEffectiveDependencies().stream().anyMatch(d -> d.getGroupId().equals(ACTUATOR_GROUP_ID) && d.getArtifactId().equals(ACTUATOR_ARTIFACT_ID)))
55+
.sorted(Comparator.comparing(ProjectResource::getSourcePath))
56+
.collect(Collectors.toList());
57+
}
58+
59+
@Override
60+
public Map<String, List<BuildFile>> getData() {
61+
return Map.of("matchingBuildFiles", buildFilesWithActuatorOnClasspath);
62+
}
63+
}

components/sbm-recipes-boot-upgrade/src/main/resources/recipes/27_30/report/sbu30-report.yaml

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,20 @@
8787
sections:
8888

8989

90-
- title: Add Spring Boot dependency and plugin milestone repository
91-
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.AddSpringBootRepositoriesHelper
92-
change: |-
93-
As currently only milestone releases exist these are required
94-
affected: |-
95-
You want to update to 3.0 so you're affected
96-
remediation:
97-
description: |-
98-
Add Spring Boot milestone repositories.
99-
recipe: sbu30-add-milestone-repositories
100-
gitHubIssue: 441
101-
contributors:
102-
- "Fabian Krüger[@fabapp2]"
90+
# Note re required anymore now that 3.0 is released. Kept for reference
91+
# - title: Add Spring Boot dependency and plugin milestone repository
92+
# helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.AddSpringBootRepositoriesHelper
93+
# change: |-
94+
# As currently only milestone releases exist these are required
95+
# affected: |-
96+
# You want to update to 3.0 so you're affected
97+
# remediation:
98+
# description: |-
99+
# Add Spring Boot milestone repositories.
100+
# recipe: sbu30-add-milestone-repositories
101+
# gitHubIssue: 441
102+
# contributors:
103+
# - "Fabian Krüger[@fabapp2]"
103104

104105
- title: Upgrade Dependencies
105106
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.UpgradeDependenciesHelper
@@ -132,6 +133,58 @@
132133
- "Fabian Krüger[@fabapp2]"
133134

134135

136+
- title: Actuator Endpoints Sanitization
137+
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ActuatorEndpointsSanitizationHelper
138+
change: |-
139+
Since, the `/env` and `/configprops` endpoints can contains sensitive values, all values are always masked by default.
140+
This used to be case only for keys considered to be sensitive.
141+
142+
Instead, this release opts for a more secure default.
143+
The keys-based approach has been removed in favor of a role based approach, similar to the health endpoint details.
144+
Whether unsanitized values are shown or not can be configured using a property which can have the following values:
145+
146+
- `NEVER` - All values are sanitized.
147+
- `ALWAYS` - All values are present in the output (sanitizing functions will apply).
148+
- `WHEN_AUTHORIZED` - Values are present in the output only if a user is authorized (sanitizing functions will apply).
149+
150+
For JMX, users are always considered to be authorized. For HTTP, users are considered to be authorized if they are authenticated and have the specified roles.
151+
152+
Sanitization for the QuartzEndpoint is also configurable in the same way.
153+
affected: |-
154+
The scan found a dependency to actuator on the classpath.
155+
156+
<#list matchingBuildFiles as match>
157+
* file://${match.absolutePath}[`${match.sourcePath}`]<#lt>
158+
</#list>
159+
remediation:
160+
possibilities:
161+
- title: Verify the new sanitization fulfills your requirements
162+
description: |-
163+
Please verify that none of the sanitized values must be plain text to meet your requirements.
164+
If some sanitized values are required in plain text a custom `SanitizingFunction` must be provided.
165+
Please see the documentation about https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"]
166+
for further information on how to do this.
167+
resources:
168+
- https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values[Sanitize Sensitive Values^, role="ext-link"]
169+
- https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/howto.html#howto.actuator.sanitize-sensitive-values.customizing-sanitization[Customizing Sanitization^, role="ext-link"]
170+
# Not available until upgrade to the latest rewrite version which is currently blocked
171+
#
172+
# - title: Reset behavior to prior 3.0
173+
# description: |-
174+
# Because Spring Boot Migrator can't tell if the now sanitized properties are required in plain-text,
175+
# the only automated change we can do is setting `management.endpoint.configprops.show-values`,
176+
# `management.endpoint.env.show-values` and `management.endpoint.quartz.show-values` to `ALWAYS`.
177+
# This means the application does not benefit from the new and more secure configuration in Spring Boot 3.0.0.
178+
# We strongly recommend you adjust this configuration to your needs.
179+
#
180+
# WARNING: This would result in some values not being sanitized when in 2.7 they would have been.
181+
# recipe: sbu30-225-actuator-endpoint-sanitization
182+
projects:
183+
- spring-boot
184+
gitHubIssue: 445
185+
contributors:
186+
- "Fabian Krüger[@fabapp2]"
187+
135188
- title: Changes to Data Properties
136189
helper: org.springframework.sbm.boot.upgrade_27_30.report.helper.ChangesToDataPropertiesHelper
137190
change: |-
@@ -226,8 +279,8 @@
226279
`@Autowired` annotation.
227280
sources:
228281
- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0.0-M2-Release-Notes#constructingbinding-no-longer-needed-at-the-type-level[Spring Boot Release Notes]
229-
- https://docs.spring.io/spring-boot/docs/3.0.0-M4/api/org/springframework/boot/context/properties/ConstructorBinding.html[@ConstructorBinding API]
230-
- https://docs.spring.io/spring-boot/docs/3.0.0-M4/api/org/springframework/boot/context/properties/ConfigurationProperties.html[@ConfigurationProperties API]
282+
- https://docs.spring.io/spring-boot/docs/3.0.0/api/org/springframework/boot/context/properties/ConstructorBinding.html[@ConstructorBinding API]
283+
- https://docs.spring.io/spring-boot/docs/3.0.0/api/org/springframework/boot/context/properties/ConfigurationProperties.html[@ConfigurationProperties API]
231284
affected: |-
232285
We found usage of `@ConstructorBinding` in following files:
233286
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright 2021 - 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.sbm.boot.upgrade_27_30.report.helper;
17+
18+
import org.assertj.core.api.Assertions;
19+
import org.junit.jupiter.api.Nested;
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.sbm.build.util.PomBuilder;
22+
import org.springframework.sbm.engine.context.ProjectContext;
23+
import org.springframework.sbm.project.resource.TestProjectContext;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
import static org.junit.jupiter.api.Assertions.*;
27+
28+
/**
29+
* @author Fabian Krüger
30+
*/
31+
class ActuatorEndpointsSanitizationHelperTest {
32+
33+
@Test
34+
void withSingleModuleApplication() {
35+
ProjectContext context = TestProjectContext
36+
.buildProjectContext()
37+
.withSpringBootParentOf("3.0.0")
38+
.withBuildFileHavingDependencies("org.springframework.boot:spring-boot-actuator")
39+
.build();
40+
41+
ActuatorEndpointsSanitizationHelper sut = new ActuatorEndpointsSanitizationHelper();
42+
assertThat(sut.evaluate(context)).isTrue();
43+
assertThat(sut.getData()).hasSize(1);
44+
assertThat(sut.getData().get("matchingBuildFiles")).containsExactly(context.getApplicationModules().getRootModule().getBuildFile());
45+
}
46+
47+
@Test
48+
void withMultiModuleApplication() {
49+
String parentPom = PomBuilder
50+
.buildParentPom("org.springframework.boot:spring-boot-starter-parent:3.0.0", "com.example:parent:1.0")
51+
.withModules("moduleA", "moduleB", "moduleC")
52+
.build();
53+
String moduleA = PomBuilder
54+
.buildPom("com.example:parent:1.0", "moduleA")
55+
.compileScopeDependencies("com.example:moduleC:1.0")
56+
.build();
57+
String moduleB = PomBuilder
58+
.buildPom("com.example:parent:1.0", "moduleB")
59+
.compileScopeDependencies("com.example:moduleC:1.0")
60+
.build();
61+
String moduleC = PomBuilder
62+
.buildPom("com.example:parent:1.0", "moduleC")
63+
.compileScopeDependencies("org.springframework.boot:spring-boot-starter-actuator")
64+
.build();
65+
66+
ProjectContext context = TestProjectContext
67+
.buildProjectContext()
68+
.withMavenRootBuildFileSource(parentPom)
69+
.withMavenBuildFileSource("moduleA", moduleA)
70+
.withMavenBuildFileSource("moduleB", moduleB)
71+
.withMavenBuildFileSource("moduleC", moduleC)
72+
.build();
73+
74+
ActuatorEndpointsSanitizationHelper sut = new ActuatorEndpointsSanitizationHelper();
75+
assertThat(sut.evaluate(context)).isTrue();
76+
assertThat(sut.getData().get("matchingBuildFiles")).hasSize(3);
77+
assertThat(sut.getData().get("matchingBuildFiles")).containsExactly(
78+
context.getApplicationModules().getModule("moduleA").getBuildFile(),
79+
context.getApplicationModules().getModule("moduleB").getBuildFile(),
80+
context.getApplicationModules().getModule("moduleC").getBuildFile()
81+
);
82+
}
83+
84+
}

0 commit comments

Comments
 (0)