SonarQube Vulnerability while using File class in Java - java

Objective: The batch application needs to read a file from the server. The exact directory might change in future and so we should make it dynamic.
Approach taken: The file path (directories) and the file name will be provided in the application yaml file as follows:
file path: /application/directory
file name: test.csv
Code for the same:
Initial version:
File file = new File(filePath,filename);
SonarQube showed it vulnerable by suggesting this:
A file is opened to read its content. The filename comes from an input parameter. If an unfiltered parameter is passed to this file API, files from an arbitrary filesystem location could be read.
This rule identifies potential path traversal vulnerabilities. In many cases, the constructed file path cannot be controlled by the user. If that is the case, the reported instance is a false positive.
Vulnerable Code:
#GET
#Path("/images/{image}")
#Produces("images/*")
public Response getImage(#javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", image); //Weak point
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
Solution:
import org.apache.commons.io.FilenameUtils;
#GET
#Path("/images/{image}")
#Produces("images/*")
public Response getImage(#javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", FilenameUtils.getName(image)); //Fix
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
I have changed my code accordingly:
File file = new File(filePath,FilenameUtils.getName(fileName));
Still I am getting the same error message.

Yes it is a False Positive.
I removed this by using //NOSONAR at the end of the statement
File file = new File("resources/images/", FilenameUtils.getName(image)); //NOSONAR

Related

java.nio.file.NoSuchFileException When File.transferTo() is called

I've recently inherited a Java API and am having trouble with file uploads. Unfortunately, Java isn't a language I have much experience in so I'm a bit stumped by this.
The MultiPartFile is being received ok, and I can find the file in the temp directory, but when I try to use File.transferTo() to create the final file I just get the below error;
java.nio.file.NoSuchFileException: C:\Users\myUser\AppData\Local\Temp\undertow3706399294849267898upload -> S:\Dev\PolicyData\Temp.xlsx
As I mentioned the temp undertow file exists, and the directory on the S drive also exist, (but there's no Temp.xlsx as my understanding is this should be created by transferTo()). Any solutions I've found to this problem so far are resolved using absolute file paths.
This is a simplified version of the code but the error remains the same.
SpringBoot framework is "1.5.3.RELEASE", running Java 1.8.0_131
ResponseEntity handleFileUpload(#RequestPart(name = "file") MultipartFile file, #PathVariable Long stageFileTypeId) {
if (!file.isEmpty()) {
try {
String filePath = "S:\\Dev\\PolicyData\\Temp.xlsx";
log.info("Upload Path = {}", filePath);
File dest = new File(filePath);
file.transferTo(dest);
return ResponseUtil.wrapOrNotFound(Optional.ofNullable(filePath));
}
catch (Exception ex) {
log.error("An error has occurred uploading the file", ex);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
else {
log.error("An error has occurred, no file was received");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
If you need any more information please let me know.
Thanks,
Neil
The API for MultipartFile is a bit tricky. The transferTo(File) method javadoc states that (bold are mine):
This may either move the file in the filesystem, copy the file in the
filesystem, or save memory-held contents to the destination file. If
the destination file already exists, it will be deleted first.
If the target file has been moved in the filesystem, this operation
cannot be invoked again afterwards. Therefore, call this method just
once in order to work with any storage mechanism.
It seems that the Undertow implementantion already called it to move the in-memory uploaded file to "C:\Users\myUser\AppData\Loca\Temp\undertow3706399294849267898upload" so another transferTo is failing.
I came across the same problem using javax.servlet.http.Part in a Wildfly containter with Undertow.
If you are using Spring framework >= 5.1, you could try the Multipart.transferTo(Path) method, using dest.toPath()
Or you can copy from the inputStream, with something like this:
try (InputStream is = multipartFile.getInputStream()) {
Files.copy(is, dest.toPath());
}

Java annotation processing edit file created by annotation processer with other annotation processor

I am trying to generate a config file for my sourcecode via compiletime annotation processing in Java 8.
As far as I understand for each Annotation listed in the getSupportedAnnotationTypes class, the processor gets called once.
#Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> set = new LinkedHashSet<>();
set.add(MCPlugin.class.getCanonicalName());
set.add(MCAPIVersion.class.getCanonicalName());
set.add(MCAuthor.class.getCanonicalName());
set.add(MCAPIVersion.class.getCanonicalName());
set.add(MCDepend.class.getCanonicalName());
set.add(MCLoad.class.getCanonicalName());
set.add(MCLoadBefore.class.getCanonicalName());
set.add(MCSoftDepend.class.getCanonicalName());
set.add(MCCommand.class.getCanonicalName());
return set;
}
Actually I don't want to process all those annotations with one annotation processer (Would this be the right way?) because it causes problems with the MCCommand annotation.
So my plan was to create another annotation processer, which only processes the MCCommand annotations.
My problem is, that the output of both processers should go into the same output file. (Is that even possible?)
I have already tried to reopen the resource file like this (this is also how I open it in the first place):
FileObject file = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "config.yml");
which will only create an error or override the existing file.
TlDr: How can I make my annotation processer edit a file generated by another annotation processor?
Okay, after hours of going through the sourcecode of the Filer and the FileObject I found a solution / workaround.
To be able to get access to the JavacFiler you need to have com.sun.tools as dependency.
Downcast the Filer to a JavacFiler to get access to more methods.
The filer has a createResource(...) and a getResource(...) method, which seem to do the same but the difference is that createResource(...) opens a FileObject for writing only and the getResource(...) for reading only.
So to be able to edit a file from another Annotation Processor you have to do:
open the file as read read only
read the filecontent
close the file
reopen the file as write only
write the old content to it
add more data
FileObject jfo = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt");
String msg = TUtils.JFOToString(jfo); // Reads FileObject as String
jfo.delete();
jfo = filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "test.txt");
TUtils.writeJFO(jfo, msg + "Hallo ich bin Processor 2"); // Writes String to FileObject
filer.close();
This feels like a hack, but I seems to work.
I know this is old, but it might help other people.
You can identify the file path and edit it as normal file (delete, truncate, append...).
In the process, the file will be created if it does not exist. But the content will not be deleted.
public Path createIdentifyResource(String file) throws IOException {
try {
FileObject fileObject = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT,
"", file);
return new File(fileObject.toUri()).toPath();
} catch (IOException e) {
FileObject fileObject = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT,
"", file);
return new File(fileObject.toUri()).toPath();
}
}
The process is simple. First try to get the resource as if it exists. If it fails, it will attempt to create the resource. Finally, get the URI and convert it to Path.

How to write to a file in Android (without FileNotFoundException Error)

I am having some issues writing to a file in my internal storage in Android. What I am wanting to achieve, is it first of all check whether there is a file (of specified name) already existing in the internal storage. If there isn't, I would then like it to create a file with that name, and write specified content to it. If there is already a file, I would simply like it to write specified content appended to what is already stored within the file. I think I have found how I can check if the file is in existence, and also create a new blank file with the specified name if it isn't (see code below). However, when coming to write to the file I get an error message java.io.FileNotFoundException error, even though my code should ensure that there will always be a file in existence to open with the FileOutputStream. Please could anyone tell me what I am doing wrong. Thanks in advance.
public boolean isFilePresent() {
String strASANo = getIntent().getStringExtra("strASA"); //Part of File Name imported passed from parameter
String logsFile = strASANo + "logs";
File file = getBaseContext().getFileStreamPath(logsFile);
return file.exists();
}
//////////////////////////////////////////////////////////////////////////////
public void addSaveClick(View view) {
if (!isFilePresent()) {
File file = new File(getApplicationContext().getFilesDir(), logsFile);
}
FileOutputStream logWriter;
try {
logWriter = openFileOutput(logsFile, MODE_APPEND); //Unhandled Exception: java.io.FileNotFoundException
}
}

Is there a way to get the file path of the .java file executed or compiled?

In Python the global variable __file__ is the full path of the current file.
System.getProperty("user.dir"); seems to return the path of the current working directory.
I want to get the path of the current .java, .class or package file.
Then use this to get the path to an image.
My project file structure in Netbeans looks like this:
(source: toile-libre.org)
Update to use code suggested from my chosen best answer:
// read image data from picture in package
try {
InputStream instream = TesseractTest.class
.getResourceAsStream("eurotext.tif");
bufferedImage = ImageIO.read(instream);
}
catch (IOException e) {
System.out.println(e.getMessage());
}
This code is used in the usage example from tess4j.
My full code of the usage example is here.
If you want to load an image file stored right next to your class file, use Class::getResourceAsStream(String name).
In your case, that would be:
try (InputStream instream = TesseractTest.class.getResourceAsStream("eurotext.tif")) {
// read stream here
}
This assumes that your build system copies the .tif file to your build folder, which is commonly done by IDEs, but requires extra setup in build tools like Ant and Gradle.
If you package your program to a .jar file, the code will still work, again assuming your build system package the .tif file next to the .class file.
Is there a way to get the file path of the .java file executed or compiled?
For completeness, the literal answer to your question is "not easily and not always".
There is a round-about way to find the source filename for a class on the callstack via StackFrameElement.getFileName(). However, the filename won't always be available1 and it won't necessarily be correct2.
Indeed, it is quite likely that the source tree won't be present on the system where you are executing the code. So if you needed an image file that was stashed in the source tree, you would be out of luck.
1 - It depends on the Java compiler and compilation options that you use. And potentially on other things.
2 - For example, the source tree can be moved or removed after compilation.
Andreas has described the correct way to solve your problem. Make sure that the image file is in your application's JAR file, and access it using getResource or getResourceAsStream. If your application is using an API that requires a filename / pathname in the file system, you may need to extract the resource from the JAR to a temporary file, or something like that.
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(getPackageParent(Main.class, false));
}
public static String getPackageParent(Class<?> cls, boolean include_last_dot)
throws Exception {
StringBuilder sb = new StringBuilder(cls.getPackage().getName());
if (sb.lastIndexOf(".") > 0)
if (include_last_dot)
return sb.delete(sb.lastIndexOf(".") + 1, sb.length())
.toString();
else
return sb.delete(sb.lastIndexOf("."), sb.length()).toString();
return sb.toString();
}
}

FileNotFoundException when writing new xsd file

I have parsed a batch of XML Schema files using a DOMparser. I than added several annotations, which are essential for the application I am creating. I then want to write these new "preprocessed" files to a new location, and I get a FileNotFound exception (access denied).
Here's the snippet of code where I am writing the file:
Transformer tFormer = TransformerFactory.newInstance().newTransformer();
// Set output file to xml
tFormer.setOutputProperty(OutputKeys.METHOD, "xml");
// Write the document back to the file
Source source = new DOMSource(document);
File preprFile = new File(newPath(xmlFile));
// The newPath function is a series of String operations that result in a new
relative path
try {
// Create file if it doesn't already exist;
preprFile.mkdirs();
preprFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
Result result = new StreamResult(preprFile);
tFormer.transform(source, result);
And the error I am getting is the following:
java.io.FileNotFoundException: absolutePathHere (Access is denied)
Which points to this line in the above snippet :
tFormer.transform(source, result);
I'm using a Windows machine (read somewhere that that can be the source of this error), and I've already tried turning UAC off, but no success.
I was thinking maybe the createNewFile() method doesn't release the file after it's been made, but was unable to find more information about that.
Here's hoping StackOverflow can come to my rescue once again.
It's probably running under a user account that doesn't have the rights to that directory.
You said "The directory is created, and it appears the file is created as a directory as well". So I think it creates directory named 'wsreportkbo_messages.xsd'
It gives you error may be because you are trying to read directory. You can list files in directories using listFiles().
You cannot open and read a directory, use the isFile() and isDirectory() methods to distinguish between files and folders.
I found the solution:
File preprFile = new File(directory1/directory2/directory3/file.xsd);
File directory = new File(directory1/directory2/directory3/);
try {
// Create file if it doesn't already exist;
directory.mkdirs();
preprFile.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
Thanks for the help.

Categories