Skip to content

Commit 8e013b6

Browse files
committed
Merge branch '3.5.x' into 4.0.x
Closes gh-50178
2 parents fd70564 + 5ceb1a2 commit 8e013b6

2 files changed

Lines changed: 82 additions & 4 deletions

File tree

core/spring-boot/src/main/java/org/springframework/boot/system/ApplicationTemp.java

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@
1818

1919
import java.io.File;
2020
import java.io.IOException;
21+
import java.io.UncheckedIOException;
2122
import java.nio.file.FileSystem;
2223
import java.nio.file.Files;
24+
import java.nio.file.LinkOption;
2325
import java.nio.file.Path;
2426
import java.nio.file.Paths;
2527
import java.nio.file.attribute.FileAttribute;
28+
import java.nio.file.attribute.PosixFileAttributes;
2629
import java.nio.file.attribute.PosixFilePermission;
2730
import java.nio.file.attribute.PosixFilePermissions;
31+
import java.nio.file.attribute.UserPrincipal;
2832
import java.security.MessageDigest;
2933
import java.util.EnumSet;
3034
import java.util.HexFormat;
@@ -56,6 +60,8 @@ public class ApplicationTemp {
5660

5761
private final Lock pathLock = new ReentrantLock();
5862

63+
private final @Nullable UserPrincipal directoryOwner;
64+
5965
private volatile @Nullable Path path;
6066

6167
/**
@@ -71,6 +77,22 @@ public ApplicationTemp() {
7177
*/
7278
public ApplicationTemp(@Nullable Class<?> sourceClass) {
7379
this.sourceClass = sourceClass;
80+
this.directoryOwner = directoryOwner();
81+
}
82+
83+
private static @Nullable UserPrincipal directoryOwner() {
84+
try {
85+
Path tempFile = Files.createTempFile("application-temp", "-owner");
86+
UserPrincipal owner = Files.getOwner(tempFile);
87+
Files.delete(tempFile);
88+
return owner;
89+
}
90+
catch (UnsupportedOperationException ex) {
91+
return null;
92+
}
93+
catch (IOException ex) {
94+
throw new UncheckedIOException(ex);
95+
}
7496
}
7597

7698
@Override
@@ -115,8 +137,28 @@ private Path getPath() {
115137

116138
private Path createDirectory(Path path) {
117139
try {
118-
if (!Files.exists(path)) {
119-
Files.createDirectory(path, getFileAttributes(path.getFileSystem(), DIRECTORY_PERMISSIONS));
140+
FileSystem fileSystem = path.getFileSystem();
141+
if (!Files.exists(path, LinkOption.NOFOLLOW_LINKS)) {
142+
Files.createDirectory(path, asFileAttributes(fileSystem, DIRECTORY_PERMISSIONS));
143+
}
144+
else {
145+
if (supportsPosixView(fileSystem)) {
146+
PosixFileAttributes attributes = Files.readAttributes(path, PosixFileAttributes.class,
147+
LinkOption.NOFOLLOW_LINKS);
148+
Assert.state(attributes.isDirectory(),
149+
() -> "'" + path + "' already exists but it is not a directory");
150+
Assert.state(DIRECTORY_PERMISSIONS.equals(attributes.permissions()), () -> "Existing directory '"
151+
+ path + "' does not have the permissions " + DIRECTORY_PERMISSIONS);
152+
assertDirectoryOwnership(attributes.owner(), path);
153+
}
154+
else {
155+
try {
156+
assertDirectoryOwnership(Files.getOwner(path, LinkOption.NOFOLLOW_LINKS), path);
157+
}
158+
catch (UnsupportedOperationException ex) {
159+
// Ownership check not supported. Continue.
160+
}
161+
}
120162
}
121163
return path;
122164
}
@@ -125,13 +167,24 @@ private Path createDirectory(Path path) {
125167
}
126168
}
127169

128-
private FileAttribute<?>[] getFileAttributes(FileSystem fileSystem, EnumSet<PosixFilePermission> ownerReadWrite) {
129-
if (!fileSystem.supportedFileAttributeViews().contains("posix")) {
170+
private void assertDirectoryOwnership(UserPrincipal owner, Path path) {
171+
if (this.directoryOwner != null) {
172+
Assert.state(this.directoryOwner.equals(owner),
173+
() -> "Existing directory '" + path + "' is not owned by " + this.directoryOwner.getName());
174+
}
175+
}
176+
177+
private FileAttribute<?>[] asFileAttributes(FileSystem fileSystem, EnumSet<PosixFilePermission> ownerReadWrite) {
178+
if (!supportsPosixView(fileSystem)) {
130179
return NO_FILE_ATTRIBUTES;
131180
}
132181
return new FileAttribute<?>[] { PosixFilePermissions.asFileAttribute(ownerReadWrite) };
133182
}
134183

184+
private boolean supportsPosixView(FileSystem fileSystem) {
185+
return fileSystem.supportedFileAttributeViews().contains("posix");
186+
}
187+
135188
private Path getTempDirectory() {
136189
String property = System.getProperty("java.io.tmpdir");
137190
Assert.state(StringUtils.hasLength(property), "No 'java.io.tmpdir' property set");

core/spring-boot/src/test/java/org/springframework/boot/system/ApplicationTempTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.nio.file.Path;
2424
import java.nio.file.attribute.PosixFileAttributeView;
2525
import java.nio.file.attribute.PosixFilePermission;
26+
import java.util.EnumSet;
2627
import java.util.Set;
2728

2829
import org.junit.jupiter.api.AfterEach;
@@ -32,6 +33,7 @@
3233
import org.springframework.util.FileSystemUtils;
3334

3435
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
3537

3638
/**
3739
* Tests for {@link ApplicationTemp}.
@@ -85,6 +87,29 @@ void posixPermissions() throws IOException {
8587
}
8688
}
8789

90+
@Test
91+
void whenDirectoryExistsWithWrongPermissionsGetDirThrows() throws IOException {
92+
ApplicationTemp temp = new ApplicationTemp();
93+
Path path = temp.getDir().toPath();
94+
Files.getFileAttributeView(path, PosixFileAttributeView.class)
95+
.setPermissions(EnumSet.allOf(PosixFilePermission.class));
96+
assertThatIllegalStateException().isThrownBy(new ApplicationTemp()::getDir)
97+
.withMessageContaining("does not have the permissions");
98+
FileSystemUtils.deleteRecursively(path);
99+
}
100+
101+
@Test
102+
void whenSymlinkExistsInDirectoryLocationGetDirThrows() throws IOException {
103+
ApplicationTemp temp = new ApplicationTemp();
104+
Path path = temp.getDir().toPath();
105+
FileSystemUtils.deleteRecursively(path);
106+
Path linkTarget = Files.createTempDirectory("application-test-tests");
107+
Files.createSymbolicLink(path, linkTarget);
108+
assertThatIllegalStateException().isThrownBy(new ApplicationTemp()::getDir)
109+
.withMessageContaining("already exists but it is not a directory");
110+
FileSystemUtils.deleteRecursively(path);
111+
}
112+
88113
private void assertDirectoryPermissions(Path path) throws IOException {
89114
Set<PosixFilePermission> permissions = Files.getFileAttributeView(path, PosixFileAttributeView.class)
90115
.readAttributes()

0 commit comments

Comments
 (0)