Skip to content

Commit

Permalink
Merge pull request #12206 from Avishka-Shamendra/master
Browse files Browse the repository at this point in the history
Improve API Doc File Upload
  • Loading branch information
dushaniw authored Jan 3, 2024
2 parents d0714fc + 80bc6c5 commit 5bc3596
Showing 1 changed file with 54 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
import java.io.*;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;

public class RestApiPublisherUtils {
Expand Down Expand Up @@ -99,14 +101,16 @@ public static void attachFileToDocument(String apiId, Documentation documentatio
//APIIdentifier apiIdentifier = APIMappingUtil
// .getAPIIdentifierFromUUID(apiId, tenantDomain);

RestApiUtil.transferFile(inputStream, filename, docFile.getAbsolutePath());
docInputStream = new FileInputStream(docFile.getAbsolutePath() + File.separator + filename);
Path resolvedPath = resolveFilePath(docFile.getAbsolutePath(), filename);

RestApiUtil.transferFile(inputStream, resolvedPath.getFileName().toString(), resolvedPath.getParent().toString());
docInputStream = new FileInputStream(resolvedPath.toString());
String mediaType = fileDetails.getHeader(RestApiConstants.HEADER_CONTENT_TYPE);
mediaType = mediaType == null ? RestApiConstants.APPLICATION_OCTET_STREAM : mediaType;
PublisherCommonUtils
.addDocumentationContentForFile(docInputStream, mediaType, filename, apiProvider, apiId,
documentId, organization);
docFile.deleteOnExit();
docFile.delete();
} catch (FileNotFoundException e) {
RestApiUtil.handleInternalServerError("Unable to read the file from path ", e, log);
} finally {
Expand Down Expand Up @@ -186,14 +190,16 @@ public static void attachFileToProductDocument(String productId, Documentation d
//APIProductIdentifier productIdentifier = APIMappingUtil
// .getAPIProductIdentifierFromUUID(productId, tenantDomain);

RestApiUtil.transferFile(inputStream, filename, docFile.getAbsolutePath());
docInputStream = new FileInputStream(docFile.getAbsolutePath() + File.separator + filename);
Path resolvedPath = resolveFilePath(docFile.getAbsolutePath(), filename);

RestApiUtil.transferFile(inputStream, resolvedPath.getFileName().toString(), resolvedPath.getParent().toString());
docInputStream = new FileInputStream(resolvedPath.toString());
String mediaType = fileDetails.getHeader(RestApiConstants.HEADER_CONTENT_TYPE);
mediaType = mediaType == null ? RestApiConstants.APPLICATION_OCTET_STREAM : mediaType;
PublisherCommonUtils
.addDocumentationContentForFile(docInputStream, mediaType, filename, apiProvider, productId,
documentId, organization);
docFile.deleteOnExit();
docFile.delete();
} catch (FileNotFoundException e) {
RestApiUtil.handleInternalServerError("Unable to read the file from path ", e, log);
} finally {
Expand Down Expand Up @@ -406,4 +412,46 @@ public static String getMediaType(InputStream inputStream, Attachment fileDetail
}
return fileMediaType;
}

/**
* Resolves an untrusted user-specified path against the base directory.
* Paths that try to escape the base directory are rejected.
* @param baseDirPathString the absolute path of the base directory that all
* user-specified paths should be within
* @param userPathString the untrusted path provided by the user
* @return Resolved Path
* @throws APIManagementException if resolution fails.
*/
private static Path resolveFilePath(final String baseDirPathString, final String userPathString) throws APIManagementException {
Path baseDirPath = Paths.get(baseDirPathString);
Path userPath = Paths.get(userPathString);
if (!baseDirPath.isAbsolute()) {
throw new APIManagementException("Invalid base path provided." +
" Base path must be absolute. Base Path: " + baseDirPath);
}

if (userPath.isAbsolute()){
throw new APIManagementException("Invalid user path provided." +
" User path should not be absolute. User Path: " + userPath);
}

/*
* Combines the absolute base directory path and the user-specified relative path.
* Then, normalizes the path to handle any ".." elements in the userPath.
* For example, if the baseDirPath is "/foo/bar/baz" and userPath is "../attack",
* the resulting resolvedPath will be "/foo/bar/attack".
*/
final Path resolvedPath = baseDirPath.resolve(userPath).normalize();

/*
* Verifies that the resolved path is still within the expected base directory.
* If the resolved path does not start with the base directory path,
* it indicates an attempt to escape the intended directory structure.
*/
if (!resolvedPath.startsWith(baseDirPath)) {
throw new APIManagementException("Error resolving path. The user path attempts to escape the base directory.");
}

return resolvedPath;
}
}

0 comments on commit 5bc3596

Please sign in to comment.