Skip to content

Commit 2391bbe

Browse files
authored
Merge branch 'master' into bump-snap-2.4.48-SNAPSHOT
2 parents a0e34e9 + 237bde6 commit 2391bbe

24 files changed

+475
-11
lines changed

.github/workflows/codeql.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
name: "CodeQL"
1313

1414
on:
15+
pull_request:
16+
branches: [ "master" ]
17+
push:
18+
branches: [ "master" ]
1519
schedule:
1620
- cron: '16 04 * * 2'
1721

modules/swagger-codegen/src/main/java/io/swagger/codegen/AbstractGenerator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.Scanner;
1414
import java.util.regex.Pattern;
1515

16+
import io.swagger.codegen.utils.SecureFileUtils;
1617
import org.apache.commons.lang3.StringUtils;
1718
import org.slf4j.Logger;
1819
import org.slf4j.LoggerFactory;
@@ -23,6 +24,7 @@ public abstract class AbstractGenerator {
2324
@SuppressWarnings("static-method")
2425
public File writeToFile(String filename, String contents) throws IOException {
2526
LOGGER.info("writing file " + filename);
27+
SecureFileUtils.validatePath(filename);
2628
File output = new File(filename);
2729

2830
if (output.getParent() != null && !new File(output.getParent()).exists()) {
@@ -106,7 +108,7 @@ public String getFullTemplateFile(CodegenConfig config, String templateFile) {
106108
return embeddedLibTemplateFile;
107109
}
108110
}
109-
111+
110112
// Fall back to the template file embedded/packaged in the JAR file...
111113
return config.embeddedTemplateDir() + File.separator + templateFile;
112114
}

modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultCodegen.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import com.samskivert.mustache.Mustache;
1616
import com.samskivert.mustache.Template;
17+
import io.swagger.codegen.utils.SecureFileUtils;
1718
import io.swagger.models.properties.UntypedProperty;
1819
import org.apache.commons.lang3.ObjectUtils;
1920
import org.apache.commons.lang3.StringEscapeUtils;
@@ -3562,6 +3563,7 @@ public String apiTestFilename(String templateName, String tag) {
35623563
}
35633564

35643565
public boolean shouldOverwrite(String filename) {
3566+
SecureFileUtils.validatePath(filename);
35653567
return !(skipOverwrite && new File(filename).exists());
35663568
}
35673569

@@ -3825,6 +3827,7 @@ public void writeOptional(String outputFolder, SupportingFile supportingFile) {
38253827
else {
38263828
folder = supportingFile.destinationFilename;
38273829
}
3830+
SecureFileUtils.validatePath(folder);
38283831
if(!new File(folder).exists()) {
38293832
supportingFiles.add(supportingFile);
38303833
} else {

modules/swagger-codegen/src/main/java/io/swagger/codegen/DefaultGenerator.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import com.samskivert.mustache.Mustache;
44
import com.samskivert.mustache.Template;
55
import io.swagger.codegen.ignore.CodegenIgnoreProcessor;
6-
import io.swagger.codegen.languages.AbstractJavaCodegen;
76
import io.swagger.codegen.utils.ImplementationVersion;
7+
import io.swagger.codegen.utils.SecureFileUtils;
88
import io.swagger.models.*;
99
import io.swagger.models.auth.OAuth2Definition;
1010
import io.swagger.models.auth.SecuritySchemeDefinition;
@@ -597,6 +597,7 @@ protected void generateSupportingFiles(List<File> files, Map<String, Object> bun
597597
if (StringUtils.isNotEmpty(support.folder)) {
598598
outputFolder += File.separator + support.folder;
599599
}
600+
SecureFileUtils.validatePath(outputFolder);
600601
File of = new File(outputFolder);
601602
if (!of.isDirectory()) {
602603
of.mkdirs();
@@ -671,6 +672,7 @@ public Reader getTemplate(String name) {
671672
// Output .swagger-codegen-ignore if it doesn't exist and wasn't explicitly created by a generator
672673
final String swaggerCodegenIgnore = ".swagger-codegen-ignore";
673674
String ignoreFileNameTarget = config.outputFolder() + File.separator + swaggerCodegenIgnore;
675+
SecureFileUtils.validatePath(ignoreFileNameTarget);
674676
File ignoreFile = new File(ignoreFileNameTarget);
675677
if (isGenerateSwaggerMetadata && !ignoreFile.exists()) {
676678
String ignoreFileNameSource = File.separator + config.getCommonTemplateDir() + File.separator + swaggerCodegenIgnore;
@@ -785,6 +787,7 @@ public List<File> generate() {
785787

786788
protected File processTemplateToFile(Map<String, Object> templateData, String templateName, String outputFilename) throws IOException {
787789
String adjustedOutputFilename = outputFilename.replaceAll("//", "/").replace('/', File.separatorChar);
790+
SecureFileUtils.validatePath(adjustedOutputFilename);
788791
if (ignoreProcessor.allowsFile(new File(adjustedOutputFilename))) {
789792
String templateFile = getFullTemplateFile(config, templateName);
790793
String template = readTemplate(templateFile);

modules/swagger-codegen/src/main/java/io/swagger/codegen/ignore/CodegenIgnoreProcessor.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.ImmutableList;
44
import io.swagger.codegen.ignore.rules.DirectoryRule;
55
import io.swagger.codegen.ignore.rules.Rule;
6+
import io.swagger.codegen.utils.SecureFileUtils;
67
import org.slf4j.Logger;
78
import org.slf4j.LoggerFactory;
89

@@ -40,7 +41,9 @@ public CodegenIgnoreProcessor(final String baseDirectory) {
4041
*/
4142
@SuppressWarnings("WeakerAccess")
4243
public CodegenIgnoreProcessor(final String baseDirectory, final String ignoreFile) {
44+
SecureFileUtils.validatePath(baseDirectory);
4345
final File directory = new File(baseDirectory);
46+
SecureFileUtils.validatePath(ignoreFile);
4447
final File targetIgnoreFile = new File(directory, ignoreFile);
4548
if (directory.exists() && directory.isDirectory()) {
4649
loadFromFile(targetIgnoreFile);
@@ -55,6 +58,7 @@ public CodegenIgnoreProcessor(final String baseDirectory, final String ignoreFil
5558
* @param targetIgnoreFile The ignore file location.
5659
*/
5760
public CodegenIgnoreProcessor(final File targetIgnoreFile) {
61+
SecureFileUtils.validatePath(targetIgnoreFile);
5862
loadFromFile(targetIgnoreFile);
5963
}
6064

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaJAXRSSpecServerCodegen.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.swagger.codegen.CodegenParameter;
88
import io.swagger.codegen.CodegenProperty;
99
import io.swagger.codegen.SupportingFile;
10+
import io.swagger.codegen.utils.SecureFileUtils;
1011
import io.swagger.models.Operation;
1112
import io.swagger.models.Swagger;
1213
import io.swagger.models.parameters.Parameter;
@@ -197,6 +198,7 @@ public void preprocessSwagger(Swagger swagger) {
197198
//copy input swagger to output folder
198199
try {
199200
String swaggerJson = Json.pretty(swagger);
201+
SecureFileUtils.validatePath(outputFolder);
200202
FileUtils.writeStringToFile(new File(outputFolder + File.separator + "swagger.json"), swaggerJson, StandardCharsets.UTF_8);
201203
} catch (IOException e) {
202204
throw new RuntimeException(e.getMessage(), e.getCause());

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RubyClientCodegen.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.swagger.codegen.CodegenType;
1010
import io.swagger.codegen.DefaultCodegen;
1111
import io.swagger.codegen.SupportingFile;
12+
import io.swagger.codegen.utils.SecureFileUtils;
1213
import io.swagger.models.Model;
1314
import io.swagger.models.Operation;
1415
import io.swagger.models.Swagger;
@@ -326,7 +327,7 @@ public String generateGemName(String moduleName) {
326327
}
327328

328329
@Override
329-
public String escapeReservedWord(String name) {
330+
public String escapeReservedWord(String name) {
330331
if(this.reservedWordsMappings().containsKey(name)) {
331332
return this.reservedWordsMappings().get(name);
332333
}
@@ -741,6 +742,7 @@ public void setGemAuthorEmail(String gemAuthorEmail) {
741742
@Override
742743
public boolean shouldOverwrite(String filename) {
743744
// skip spec file as the file might have been updated with new test cases
745+
SecureFileUtils.validatePath(filename);
744746
return !(skipOverwrite && new File(filename).exists());
745747
//
746748
//return super.shouldOverwrite(filename) && !filename.endsWith("_spec.rb");

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
import java.util.Map;
77

88
import io.swagger.codegen.CliOption;
9-
import io.swagger.codegen.CodegenConstants;
9+
import io.swagger.codegen.utils.SecureFileUtils;
1010
import io.swagger.models.Model;
11-
import io.swagger.models.properties.Property;
1211
import org.apache.commons.io.FileUtils;
1312
import org.apache.commons.lang3.StringUtils;
1413
import org.slf4j.Logger;
@@ -63,6 +62,7 @@ public void processSwagger(Swagger swagger) {
6362

6463
try {
6564
String outputFile = outputFolder + File.separator + this.outputFile;
65+
SecureFileUtils.validatePath(outputFile);
6666
FileUtils.writeStringToFile(new File(outputFile), swaggerString, StandardCharsets.UTF_8);
6767
LOGGER.debug("wrote file to " + outputFile);
6868
} catch (Exception e) {

modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/SwaggerYamlGenerator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
99
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
1010
import io.swagger.codegen.*;
11+
import io.swagger.codegen.utils.SecureFileUtils;
1112
import io.swagger.jackson.mixin.OperationResponseMixin;
1213
import io.swagger.jackson.mixin.ResponseSchemaMixin;
1314
import io.swagger.models.Model;
@@ -104,6 +105,7 @@ public void processSwagger(Swagger swagger) {
104105
configureMapper(mapper);
105106
String swaggerString = mapper.writeValueAsString(swagger);
106107
String outputFile = outputFolder + File.separator + this.outputFile;
108+
SecureFileUtils.validatePath(outputFile);
107109
FileUtils.writeStringToFile(new File(outputFile), swaggerString, StandardCharsets.UTF_8);
108110
LOGGER.debug("wrote file to " + outputFile);
109111
} catch (Exception e) {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package io.swagger.codegen.utils;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
9+
10+
/**
11+
* Utility class for secure file operations that prevent path traversal attacks.
12+
* Uses a simplified approach focusing on canonical path validation and allowlist-based security.
13+
*/
14+
public class SecureFileUtils {
15+
private static final Logger LOGGER = LoggerFactory.getLogger(SecureFileUtils.class);
16+
17+
private SecureFileUtils() {
18+
// Utility class
19+
}
20+
21+
public static void validatePath(File file) {
22+
if (file == null) {
23+
LOGGER.error("File cannot be null");
24+
throw new IllegalArgumentException("File cannot be null");
25+
}
26+
27+
try {
28+
String absolutePath = file.getAbsolutePath();
29+
String canonicalPath = file.getCanonicalPath();
30+
31+
if (absolutePath.contains("..") || absolutePath.contains("\0")) {
32+
LOGGER.error("Path contains suspicious characters: {}", absolutePath);
33+
throw new SecurityException("Path contains suspicious characters: " + absolutePath);
34+
}
35+
36+
if (canonicalPath.contains("..") || canonicalPath.contains("\0")) {
37+
LOGGER.error("Path contains suspicious characters: {}", canonicalPath);
38+
throw new SecurityException("Path contains suspicious characters: " + canonicalPath);
39+
}
40+
41+
} catch (IOException e) {
42+
LOGGER.error("Unable to resolve canonical path for: {}, error: {}", file.getAbsolutePath(), e.getMessage());
43+
throw new SecurityException("Unable to resolve canonical path for: " + file.getAbsolutePath(), e);
44+
}
45+
}
46+
47+
public static void validatePath(String path) {
48+
if (path == null || path.trim().isEmpty()) {
49+
LOGGER.error("Path cannot be null or empty");
50+
throw new IllegalArgumentException("Path cannot be null or empty");
51+
}
52+
53+
if (path.contains("..") || path.contains("\0")) {
54+
LOGGER.error("Path contains suspicious characters: {}", path);
55+
throw new SecurityException("Path contains suspicious characters: " + path);
56+
}
57+
58+
validatePath(new File(path));
59+
}
60+
}

0 commit comments

Comments
 (0)