Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Knowage 8043 #891

Merged
merged 22 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
da96b6a
Revert "Possible Bugfix KNOWAGE-8043"
BojanSovticEngIT Aug 29, 2023
997e9ab
Merge remote-tracking branch 'upstream/master' into KNOWAGE-8043
BojanSovticEngIT Sep 6, 2023
e3c6a3c
Bugfix KNOWAGE-8043
BojanSovticEngIT Sep 6, 2023
aaa3d09
Merge remote-tracking branch 'upstream/master' into KNOWAGE-8043
BojanSovticEngIT Sep 13, 2023
8a66b78
Bugfix KNOWAGE-8043
BojanSovticEngIT Sep 13, 2023
09ea635
Bugfixes KNOWAGE-8043
BojanSovticEngIT Sep 18, 2023
fd75ee0
Update DossierActivityResource.java
BojanSovticEngIT Sep 18, 2023
c560439
Update SelfServiceDataSetCRUD.java
BojanSovticEngIT Sep 18, 2023
0fab752
Bugfix KNOWAGE-8043
BojanSovticEngIT Sep 19, 2023
2284ba0
Update WorksRepository.java
BojanSovticEngIT Sep 19, 2023
f302cdb
Update DossierActivityResource.java
BojanSovticEngIT Sep 19, 2023
b168ec2
Update Utils.java
BojanSovticEngIT Sep 19, 2023
9bb7574
Update SDKObjectsConverter.java
BojanSovticEngIT Sep 19, 2023
71231ad
Update SelfServiceDataSetCRUD.java
BojanSovticEngIT Sep 19, 2023
b7ecf4e
Update DossierActivityResource.java
BojanSovticEngIT Sep 19, 2023
c0dc7cc
Fixes
BojanSovticEngIT Sep 19, 2023
f0f1db5
PathTraversal fixes
BojanSovticEngIT Sep 19, 2023
45a0eff
Update PathTraversalChecker.java
BojanSovticEngIT Sep 19, 2023
6520e49
Merge remote-tracking branch 'upstream/master' into KNOWAGE-8043
BojanSovticEngIT Sep 19, 2023
ca94b0d
Bugfix Knowage-8043
BojanSovticEngIT Sep 19, 2023
fe68d3d
Bugfix Knowage-8043
BojanSovticEngIT Sep 20, 2023
6d9fa38
Update ManagePreviewFileAction.java
BojanSovticEngIT Sep 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.json.JSONException;
import org.json.JSONObject;

import it.eng.knowage.commons.security.PathTraversalChecker;
import it.eng.spagobi.commons.SingletonConfig;
import it.eng.spagobi.commons.bo.UserProfile;
import it.eng.spagobi.commons.services.AbstractSpagoBIAction;
Expand Down Expand Up @@ -107,7 +108,7 @@ public void doService() {
// checks for path traversal attacks
private void checkRequiredFile(String fileName) {
File targetDirectory = GeneralUtilities.getPreviewFilesStorageDirectoryPath();
FileUtils.checkPathTraversalAttack(fileName, targetDirectory);
PathTraversalChecker.get(targetDirectory.getName(), fileName);
}

private JSONObject uploadFile() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1227,9 +1227,10 @@ public Response uploadFile(MultiPartBody input) {
if (!(saveDirectory.exists() && saveDirectory.isDirectory())) {
saveDirectory.mkdirs();
davide-zerbetto marked this conversation as resolved.
Show resolved Hide resolved
}
String tempFile = Paths.get(saveDirectoryPath.toString(), file.getFileName()).toString();
File tempFileToSave = new File(tempFile);
PathTraversalChecker.preventPathTraversalAttack(tempFileToSave, saveDirectory);

File tempFileToSave = PathTraversalChecker.get(SpagoBIUtilities.getResourcePath(), METADATA_DIR, getUserProfile().getUserId().toString(),
file.getFileName());

tempFileToSave.createNewFile();
DataOutputStream os = new DataOutputStream(new FileOutputStream(tempFileToSave));
os.write(bytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.io.File;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
Expand Down Expand Up @@ -128,19 +127,15 @@ public String loadRandomKeyByProgressId(@PathParam("progressId") Integer progres
@GET
@Path("/resourcePath")
public Response getresourcePath(@QueryParam("templateName") String fileName, @QueryParam("documentId") Integer documentId) throws JSONException {
String separator = File.separator;
if (fileName.endsWith("?"))
fileName = fileName.substring(0, fileName.length() - 1);

java.nio.file.Path outputPath = Paths.get(SpagoBIUtilities.getResourcePath(), "dossier", String.valueOf(documentId), fileName);
File file = outputPath.toFile();
File file = PathTraversalChecker.get(SpagoBIUtilities.getResourcePath(), "dossier", "" + documentId, fileName);

ResponseBuilder responseBuilder = null;

JSONObject response = new JSONObject();
File dossierDir = new File(SpagoBIUtilities.getResourcePath() + separator + "dossier" + separator + documentId + separator);
try {
PathTraversalChecker.isValidFileName(fileName);
PathTraversalChecker.preventPathTraversalAttack(file, dossierDir);
byte[] bytes = Files.readAllBytes(file.toPath());
responseBuilder = Response.ok(bytes);
responseBuilder.header("Content-Disposition", "attachment; filename=" + fileName);
Expand All @@ -162,17 +157,13 @@ public Response getresourcePath(@QueryParam("templateName") String fileName, @Qu
@GET
@Path("/checkPathFile")
public Response checkPathFile(@QueryParam("templateName") String fileName, @QueryParam("documentId") Integer documentId) throws JSONException {
String separator = File.separator;
if (fileName.endsWith("?"))
fileName = fileName.substring(0, fileName.length() - 1);
String outPath = SpagoBIUtilities.getResourcePath() + separator + "dossier" + separator + documentId + separator + fileName;
byte[] bytes;
File file = new File(outPath);
File dossierDir = new File(SpagoBIUtilities.getResourcePath() + separator + "dossier" + separator + documentId + separator);

File file = PathTraversalChecker.get(SpagoBIUtilities.getResourcePath(), "dossier", "" + documentId, fileName);

JSONObject response = new JSONObject();
try {
PathTraversalChecker.isValidFileName(fileName);
PathTraversalChecker.preventPathTraversalAttack(file, dossierDir);
Files.readAllBytes(file.toPath());
response.put("STATUS", "OK");
} catch (Exception e) {
Expand All @@ -195,29 +186,27 @@ public Response importTemplateFile(MultiPartBody multipartFormDataInput) throws
byte[] archiveBytes = null;
JSONObject response = new JSONObject();
try {
String separator = File.separator;
final FormFile file = multipartFormDataInput.getFormFileParameterValues("file")[0];
ParameterValue[] documentIdArray = multipartFormDataInput.getParameteValues("documentId");
String identifier = "";
String path = null;

String fileName = file.getFileName();
archiveBytes = file.getContent();

File f = null;
if (documentIdArray.length == 1) {
identifier = documentIdArray[0].toString();
path = SpagoBIUtilities.getResourcePath() + separator + "dossier" + separator + identifier + separator;
f = PathTraversalChecker.get(SpagoBIUtilities.getResourcePath(), "dossier", identifier, fileName);
} else {
identifier = multipartFormDataInput.getParameteValues("uuid")[0].toString();
path = Files.createTempDirectory("prefix").getParent().resolve(identifier).toString() + separator;
f = PathTraversalChecker.get(SpagoBIUtilities.getResourcePath(), "dossier", identifier, fileName);
davide-zerbetto marked this conversation as resolved.
Show resolved Hide resolved
}

String fileName = file.getFileName();
archiveBytes = file.getContent();

File dossierDir = new File(path);
File dossierDir = new File(f.getPath());
if (!dossierDir.exists()) {
dossierDir.mkdir();
}
PathTraversalChecker.isValidFileName(fileName);
File f = new File(path + fileName);
PathTraversalChecker.preventPathTraversalAttack(f, dossierDir);

try (FileOutputStream outputStream = new FileOutputStream(f)) {
outputStream.write(archiveBytes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,7 @@ public void deleteDatasetFile(IDataSet dataset) {
FileDataSet fileDataset = (FileDataSet) wrappedDataset;
String resourcePath = fileDataset.getResourcePath();
String fileName = fileDataset.getFileName();
String filePath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar;
File datasetFile = new File(filePath + fileName);
PathTraversalChecker.preventPathTraversalAttack(datasetFile, new File(filePath));
File datasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", fileName);
if (datasetFile.exists()) {
boolean isDeleted = datasetFile.delete();
if (isDeleted) {
Expand Down Expand Up @@ -1618,11 +1616,9 @@ private JSONObject getFileDataSetConfig(SelfServiceDataSetDTO selfServiceDataSet
// This method rename a file and move it from resources\dataset\files\temp
// to resources\dataset\files
private void renameAndMoveDatasetFile(String originalFileName, String newFileName, String resourcePath, String fileType) {
String filePath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar + "temp" + File.separatorChar;
String fileNewPath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar;
File originalDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", "temp", originalFileName);
File newDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", newFileName + "." + fileType.toLowerCase());

File originalDatasetFile = new File(filePath + originalFileName);
File newDatasetFile = new File(fileNewPath + newFileName + "." + fileType.toLowerCase());
if (originalDatasetFile.exists()) {
/*
* This method copies the contents of the specified source file to the specified destination file. The directory holding the destination file is
Expand Down Expand Up @@ -1739,9 +1735,8 @@ private JSONObject getCkanDataSetConfig(SelfServiceDataSetDTO selfServiceDataSet
}

private void deleteDatasetFile(String fileName, String resourcePath, String fileType) {
String filePath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar + "temp" + File.separatorChar;
File datasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", "temp", fileName);

File datasetFile = new File(filePath + fileName);
if (datasetFile.exists()) {
datasetFile.delete();
}
Expand Down Expand Up @@ -1796,10 +1791,7 @@ private Integer getCategoryCode(String category) {

try {
ICategoryDAO categoryDao = DAOFactory.getCategoryDAO();
categories = categoryDao.getCategoriesForDataset()
.stream()
.map(Domain::fromCategory)
.collect(toList());
categories = categoryDao.getCategoriesForDataset().stream().map(Domain::fromCategory).collect(toList());
} catch (Throwable t) {
throw new SpagoBIRuntimeException("An unexpected error occured while loading categories types from database", t);
}
Expand Down Expand Up @@ -2174,10 +2166,7 @@ protected List<Integer> getCategories(IEngUserProfile profile) {
ICategoryDAO categoryDao = DAOFactory.getCategoryDAO();

// TODO : Makes sense?
List<Domain> dialects = categoryDao.getCategoriesForDataset()
.stream()
.map(Domain::fromCategory)
.collect(toList());
List<Domain> dialects = categoryDao.getCategoriesForDataset().stream().map(Domain::fromCategory).collect(toList());
if (dialects == null || dialects.size() == 0) {
return null;
}
Expand All @@ -2191,10 +2180,7 @@ protected List<Integer> getCategories(IEngUserProfile profile) {

List<RoleMetaModelCategory> aRoleCategories = roledao.getMetaModelCategoriesForRole(role.getId());
List<RoleMetaModelCategory> resp = new ArrayList<>();
List<Domain> array = categoryDao.getCategoriesForDataset()
.stream()
.map(Domain::fromCategory)
.collect(toList());
List<Domain> array = categoryDao.getCategoriesForDataset().stream().map(Domain::fromCategory).collect(toList());
for (RoleMetaModelCategory r : aRoleCategories) {
for (Domain dom : array) {
if (r.getCategoryId().equals(dom.getValueId())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ public String getDataSets(@QueryParam("includeDerived") String includeDerived, @
ISbiDataSetDAO dsDAO = DAOFactory.getSbiDataSetDAO();

List<SbiDataSet> dataSets = dsDAO.loadSbiDataSets();
List<SbiDataSet> toBeReturned = new ArrayList<SbiDataSet>();
List<SbiDataSet> toBeReturned = new ArrayList<>();

for (SbiDataSet dataset : dataSets) {
IDataSet iDataSet = DataSetFactory.toDataSet(dataset);
Expand Down Expand Up @@ -389,10 +389,7 @@ public Response downloadDataSetFile(@QueryParam("dsLabel") String dsLabel, @Quer
try {
String fileName = getFileNameFromDatasetConfiguration(myDataset);
String resourcePath = SpagoBIUtilities.getResourcePath();
File fileDirectory = new File(resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files");
file = new File(fileDirectory, fileName);

PathTraversalChecker.preventPathTraversalAttack(file, fileDirectory);
file = PathTraversalChecker.get(resourcePath, "dataset", "files", fileName);

if (file == null || !file.exists()) {
logger.error("File cannot be found");
Expand Down Expand Up @@ -583,7 +580,7 @@ public Filter getComplexFilter(InFilter inFilter, SimpleFilter anotherFilter) {
if (SimpleFilterOperator.EQUALS_TO_MIN.equals(operator) || SimpleFilterOperator.EQUALS_TO_MAX.equals(operator)) {
List<Object> operands = inFilter.getOperands();
Object result = operands.get(0);
if (result instanceof Comparable == false) {
if (!(result instanceof Comparable)) {
throw new SpagoBIRuntimeException("Unable to compare operands of type [" + result.getClass().getName() + "]");
}
Comparable comparableResult = (Comparable) result;
Expand Down Expand Up @@ -728,7 +725,7 @@ public String getDataStorePostWithJsonInBody(@PathParam("label") String label, S
Set<String> columns = null;

if (jsonIndexes != null && jsonIndexes.length() > 0) {
columns = new HashSet<String>();
columns = new HashSet<>();

for (int k = 0; k < jsonIndexes.length(); k++) {
JSONArray columnsArrayTemp = jsonIndexes.getJSONObject(k).getJSONArray("fields");
Expand Down Expand Up @@ -845,7 +842,7 @@ public String getDataStorePreview(@PathParam("label") String label, String body)
JSONObject columnsArray = columnsArrayTemp.getJSONObject(0);

if (columnsArray.getString("store").equals(label)) {
columns = new HashSet<String>(columnsArray.length());
columns = new HashSet<>(columnsArray.length());
columns.add(columnsArray.getString("column"));
}
}
Expand Down Expand Up @@ -878,15 +875,15 @@ private boolean isPreparedDAtaset(IDataSet dataSet) {
}

private Set<String> getQbeDataSetHiddenColumns(IDataSet dataSet) {
Set<String> hiddenColumns = new HashSet<String>();
Set<String> hiddenColumns = new HashSet<>();
if (dataSet.getDsType().equals("SbiQbeDataSet")) {
try {
JSONObject dsConfig = new JSONObject(dataSet.getConfiguration());
JSONObject qbeQuery = new JSONObject(dsConfig.getString("qbeJSONQuery"));
JSONArray fields = qbeQuery.getJSONObject("catalogue").getJSONArray("queries").getJSONObject(0).getJSONArray("fields");
for (int i = 0; i < fields.length(); i++) {
JSONObject field = fields.getJSONObject(i);
if (field.has("visible") && field.getBoolean("visible") == false)
if (field.has("visible") && !field.getBoolean("visible"))
hiddenColumns.add(field.getString("alias"));
}
} catch (Exception e) {
Expand All @@ -901,7 +898,7 @@ private Set<String> getQbeDataSetHiddenColumns(IDataSet dataSet) {
@Produces(MediaType.APPLICATION_JSON)
@UserConstraint(functionalities = { CommunityFunctionalityConstants.SELF_SERVICE_DATASET_MANAGEMENT })
public Response addDatasetInCache(@Context HttpServletRequest req) {
Set<String> columns = new HashSet<String>();
Set<String> columns = new HashSet<>();

logger.debug("IN");
try {
Expand Down Expand Up @@ -959,7 +956,7 @@ public String validateFormulaJson(String body) {

formulaString = jsonBody.getString("formula");
JSONArray columns = jsonBody.getJSONArray("measuresList");
List<SimpleSelectionField> l = new ArrayList<SimpleSelectionField>();
List<SimpleSelectionField> l = new ArrayList<>();

for (int i = 0; i < columns.length(); i++) {
SimpleSelectionField a = new SimpleSelectionField();
Expand Down Expand Up @@ -998,7 +995,7 @@ public ArrayList<HashMap<String, Object>> transformRuntimeDrivers(List<BusinessM
throw new SpagoBIRuntimeException(e1.getMessage(), e1);
}

HashMap<String, Object> parameterAsMap = new HashMap<String, Object>();
HashMap<String, Object> parameterAsMap = new HashMap<>();
parameterAsMap.put("id", objParameter.getBiObjectId());
parameterAsMap.put("label", objParameter.getLabel());
parameterAsMap.put("urlName", objParameter.getId());
Expand Down Expand Up @@ -1030,7 +1027,7 @@ public ArrayList<HashMap<String, Object>> transformRuntimeDrivers(List<BusinessM
List<String> valuesList = (List) paramValues;
List<String> descriptionList = (List) paramDescriptionValues;
if (paramDescriptionValues == null || !(paramDescriptionValues instanceof List)) {
descriptionList = new ArrayList<String>();
descriptionList = new ArrayList<>();
}

// String item = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -958,12 +958,9 @@ private void getPersistenceInfo(IDataSet ds, JSONObject json) {
// This method rename a file and move it from resources\dataset\files\temp
// to resources\dataset\files
private void renameAndMoveDatasetFile(String originalFileName, String newFileName, String resourcePath, String fileType) {
String filePath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar + "temp" + File.separatorChar;
String fileNewPath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar;
File originalDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", "temp", originalFileName);
File newDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", newFileName + "." + fileType.toLowerCase());

File originalDatasetFile = new File(filePath + originalFileName);
File newDatasetFile = new File(fileNewPath + newFileName + "." + fileType.toLowerCase());
PathTraversalChecker.preventPathTraversalAttack(newDatasetFile, new File(fileNewPath));
String filePathCloning = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar;
File originalDatasetFileCloning = new File(filePathCloning + originalFileName);

Expand Down Expand Up @@ -1423,7 +1420,7 @@ private FileDataSet manageFileDataSet(boolean savingDataset, JSONObject jsonDsCo
File source = new File(
SpagoBIUtilities.getResourcePath() + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar + realName);

if (!source.getCanonicalPath().equals(dest.getCanonicalPath()) && savingDataset && Boolean.TRUE.equals(!newFileUploaded)) {
if (!source.getCanonicalPath().equals(dest.getCanonicalPath()) && savingDataset && !newFileUploaded) {
LOGGER.debug("Source and destination are not the same. Copying from source to dest");
FileUtils.copyFile(source, dest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1505,12 +1505,9 @@ private RESTDataSet manageRESTDataSet(boolean savingDataset, JSONObject config)
// This method rename a file and move it from resources\dataset\files\temp
// to resources\dataset\files
private void renameAndMoveDatasetFile(String originalFileName, String newFileName, String resourcePath, String fileType) {
String filePath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar + "temp" + File.separatorChar;
String fileNewPath = resourcePath + File.separatorChar + "dataset" + File.separatorChar + "files" + File.separatorChar;
File originalDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", "temp", originalFileName);
File newDatasetFile = PathTraversalChecker.get(resourcePath, "dataset", "files", newFileName + "." + fileType.toLowerCase());

File originalDatasetFile = new File(filePath + originalFileName);
File newDatasetFile = new File(fileNewPath + newFileName + "." + fileType.toLowerCase());
PathTraversalChecker.preventPathTraversalAttack(newDatasetFile, new File(fileNewPath));
if (originalDatasetFile.exists()) {
/*
* This method copies the contents of the specified source file to the specified destination file. The directory holding the destination file is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import org.apache.log4j.Logger;

import it.eng.knowage.commons.security.PathTraversalChecker;
import it.eng.spago.security.IEngUserProfile;
import it.eng.spagobi.services.proxy.DocumentExecuteServiceProxy;
import it.eng.spagobi.utilities.mime.MimeUtils;
Expand All @@ -56,38 +57,18 @@ public void service(HttpServletRequest request, HttpServletResponse response) {

ServletOutputStream ouputStream = null;
InputStream fis = null;
File imageTmpDir = null;
File imageFile = null;
String completeImageFileName = null;
String mimeType = null;

if (chartLabel == null) {
String tmpDir = System.getProperty("java.io.tmpdir");
String imageDirectory = tmpDir.endsWith(File.separator) ? tmpDir + "birt" : tmpDir + File.separator + "birt";
imageTmpDir = new File(imageDirectory);

String imageFileName = request.getParameter("imageID");
if (imageFileName == null) {
logger.error("Image directory or image file name missing.");
throw new RuntimeException("Image file name missing.");
}

// gets complete image file name:
completeImageFileName = imageDirectory + File.separator + imageFileName;

imageFile = new File(completeImageFileName);

File parent = imageFile.getParentFile();
// Prevent directory traversal (path traversal) attacks
if (!imageTmpDir.equals(parent)) {
logger.error("Trying to access the file [" + imageFile.getAbsolutePath() + "] that is not inside ${java.io.tmpdir}/birt!!!");
throw new SecurityException("Trying to access the file [" + imageFile.getAbsolutePath() + "] that is not inside ${java.io.tmpdir}/birt!!!");
}

if (!imageFile.exists()) {
logger.error("File " + imageFile.getPath() + " not found");
return;
}
davide-zerbetto marked this conversation as resolved.
Show resolved Hide resolved
imageFile = PathTraversalChecker.get(System.getProperty("java.io.tmpdir"), "birt", imageFileName);

try {
fis = new FileInputStream(imageFile);
Expand Down
Loading