File path injection with the JFinal framework

This commit is contained in:
luchua-bc
2022-01-23 18:07:48 +00:00
parent 8e40899dfd
commit 27043a09b3
12 changed files with 855 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
// BAD: no file download validation
HttpServletRequest request = getRequest();
String path = request.getParameter("path");
String filePath = "/pages/" + path;
HttpServletResponse resp = getResponse();
File file = new File(filePath);
resp.getOutputStream().write(file.readContent());
// BAD: no file upload validation
String savePath = getPara("dir");
File file = getFile("fileParam").getFile();
FileInputStream fis = new FileInputStream(file);
String filePath = "/files/" + savePath;
FileOutputStream fos = new FileOutputStream(filePath);
// GOOD: check for a trusted prefix, ensuring path traversal is not used to erase that prefix:
// (alternatively use `Path.normalize` instead of checking for `..`)
if (!filePath.contains("..") && filePath.hasPrefix("/pages")) { ... }
// Also GOOD: check for a forbidden prefix, ensuring URL-encoding is not used to evade the check:
// (alternatively use `URLDecoder.decode` before `hasPrefix`)
if (filePath.hasPrefix("/files") && !filePath.contains("%")) { ... }

View File

@@ -0,0 +1,39 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>External Control of File Name or Path, also called File Path Injection, is a vulnerability that a file path
being accessed is composed using data from outside the application (such as the HTTP request, the database, or
the filesystem). It allows an attacker to traverse through the filesystem and access arbitrary files.</p>
</overview>
<recommendation>
<p>Unsanitized user provided data must not be used to construct the file path. In order to prevent File
Path Injection, it is recommended to avoid concatenating user input directly into the file path. Instead,
user input should be checked against allowed (e.g., must come within <code>user_content/</code>) or disallowed
(e.g. must not come within <code>/internal</code>) paths, ensuring that neither path traversal using <code>../</code>
or URL encoding are used to evade these checks.
</p>
</recommendation>
<example>
<p>The following examples show the bad case and the good case respectively.
The <code>BAD</code> methods show an HTTP request parameter being used directly to construct a file path
without validating the input, which may cause file leakage. In the <code>GOOD</code> method, file path
is validated.
</p>
<sample src="FilePathInjection.java" />
</example>
<references>
<li>OWASP:
<a href="https://owasp.org/www-community/attacks/Path_Traversal">Path Traversal</a>.
</li>
<li>Veracode:
<a href="https://www.veracode.com/security/dotnet/cwe-73">External Control of File Name or Path Flaw</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,55 @@
/**
* @name File Path Injection
* @description Loading files based on unvalidated user-input may cause file information disclosure
* and uploading files with unvalidated file types to an arbitrary directory may lead to
* Remote Command Execution (RCE).
* @kind path-problem
* @problem.severity error
* @precision high
* @id java/file-path-injection
* @tags security
* external/cwe-073
*/
import java
import semmle.code.java.dataflow.FlowSources
import JFinalController
import PathSanitizer
import DataFlow::PathGraph
/**
* A sink that represents a file read operation.
*/
private class ReadFileSinkModels extends SinkModelCsv {
override predicate row(string row) {
row =
[
"java.io;FileInputStream;false;FileInputStream;;;Argument[0];read-file",
"java.io;File;false;File;;;Argument[0];read-file"
]
}
}
/**
* A sink that represents a file creation or access, such as a file read, write, copy or move operation.
*/
private class FileAccessSink extends DataFlow::Node {
FileAccessSink() { sinkNode(this, "create-file") or sinkNode(this, "read-file") }
}
class InjectFilePathConfig extends TaintTracking::Configuration {
InjectFilePathConfig() { this = "InjectFilePathConfig" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof FileAccessSink }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof PathTraversalBarrierGuard
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, InjectFilePathConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "External control of file name or path due to $@.",
source.getNode(), "user-provided value"

View File

@@ -0,0 +1,44 @@
import java
import semmle.code.java.dataflow.FlowSources
/** The class `com.jfinal.config.Routes`. */
class JFinalRoutes extends RefType {
JFinalRoutes() { this.hasQualifiedName("com.jfinal.config", "Routes") }
}
/** The method `add` of the class `Routes`. */
class AddJFinalRoutes extends Method {
AddJFinalRoutes() {
this.getDeclaringType() instanceof JFinalRoutes and
this.getName() = "add"
}
}
/** The class `com.jfinal.core.Controller`. */
class JFinalController extends RefType {
JFinalController() { this.hasQualifiedName("com.jfinal.core", "Controller") }
}
/** Source model of remote flow source with `JFinal`. */
private class JFinalControllerSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
"com.jfinal.core;Controller;true;getAttr" + ["", "ForInt", "ForStr"] +
";;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getCookie" + ["", "Object", "Objects", "ToInt", "ToLong"] +
";;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getFile" + ["", "s"] + ";;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getHeader;;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getKv;;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getPara" +
[
"", "Map", "ToBoolean", "ToDate", "ToInt", "ToLong", "Values", "ValuesToInt",
"ValuesToLong"
] + ";;;ReturnValue;remote",
"com.jfinal.core;Controller;true;getSession" + ["", "Attr"] + ";;;ReturnValue;remote",
"com.jfinal.core;Controller;true;get" + ["", "Int", "Long", "Boolean", "Date"] +
";;;ReturnValue;remote"
]
}
}

View File

@@ -0,0 +1,175 @@
import java
import semmle.code.java.controlflow.Guards
import semmle.code.java.dataflow.FlowSources
/** A barrier guard that protects against path traversal vulnerabilities. */
abstract class PathTraversalBarrierGuard extends DataFlow::BarrierGuard { }
/**
* A guard that considers safe a string being exactly compared to a trusted value.
*/
private class ExactStringPathMatchGuard extends PathTraversalBarrierGuard instanceof MethodAccess {
ExactStringPathMatchGuard() {
super.getMethod().getDeclaringType() instanceof TypeString and
super.getMethod().getName() = ["equals", "equalsIgnoreCase"]
}
override predicate checks(Expr e, boolean branch) {
e = super.getQualifier() and
branch = true
}
}
private class AllowListGuard extends Guard instanceof MethodAccess {
AllowListGuard() {
(isStringPartialMatch(this) or isPathPartialMatch(this)) and
not isDisallowedWord(super.getAnArgument())
}
Expr getCheckedExpr() { result = super.getQualifier() }
}
/**
* A guard that considers a path safe because it is checked against an allowlist of partial trusted values.
* This requires additional protection against path traversal, either another guard (`PathTraversalGuard`)
* or a sanitizer (`PathNormalizeSanitizer`), to ensure any internal `..` components are removed from the path.
*/
private class AllowListBarrierGuard extends PathTraversalBarrierGuard instanceof AllowListGuard {
override predicate checks(Expr e, boolean branch) {
e = super.getCheckedExpr() and
branch = true and
(
// Either a path normalization sanitizer comes before the guard,
exists(PathNormalizeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
or
// or a check like `!path.contains("..")` comes before the guard
exists(PathTraversalGuard previousGuard |
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
previousGuard.controls(this.getBasicBlock().(ConditionBlock), false)
)
)
}
}
/**
* A guard that considers a path safe because it is checked for `..` components, having previously
* been checked for a trusted prefix.
*/
private class DotDotCheckBarrierGuard extends PathTraversalBarrierGuard instanceof PathTraversalGuard {
override predicate checks(Expr e, boolean branch) {
e = super.getCheckedExpr() and
branch = false and
// The same value has previously been checked against a list of allowed prefixes:
exists(AllowListGuard previousGuard |
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
previousGuard.controls(this.getBasicBlock().(ConditionBlock), true)
)
}
}
private class BlockListGuard extends Guard instanceof MethodAccess {
BlockListGuard() {
(isStringPartialMatch(this) or isPathPartialMatch(this)) and
isDisallowedWord(super.getAnArgument())
}
Expr getCheckedExpr() { result = super.getQualifier() }
}
/**
* A guard that considers a string safe because it is checked against a blocklist of known dangerous values.
* This requires a prior check for URL encoding concealing a forbidden value, either a guard (`UrlEncodingGuard`)
* or a sanitizer (`UrlDecodeSanitizer`).
*/
private class BlockListBarrierGuard extends PathTraversalBarrierGuard instanceof BlockListGuard {
override predicate checks(Expr e, boolean branch) {
e = super.getCheckedExpr() and
branch = false and
(
// Either `e` has been URL decoded:
exists(UrlDecodeSanitizer sanitizer | DataFlow::localExprFlow(sanitizer, e))
or
// or `e` has previously been checked for URL encoding sequences:
exists(UrlEncodingGuard previousGuard |
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
previousGuard.controls(this.getBasicBlock(), false)
)
)
}
}
/**
* A guard that considers a string safe because it is checked for URL encoding sequences,
* having previously been checked against a block-list of forbidden values.
*/
private class URLEncodingBarrierGuard extends PathTraversalBarrierGuard instanceof UrlEncodingGuard {
override predicate checks(Expr e, boolean branch) {
e = super.getCheckedExpr() and
branch = false and
exists(BlockListGuard previousGuard |
DataFlow::localExprFlow(previousGuard.getCheckedExpr(), e) and
previousGuard.controls(this.getBasicBlock(), false)
)
}
}
/**
* Holds if `ma` is a call to a method that checks a partial string match.
*/
private predicate isStringPartialMatch(MethodAccess ma) {
ma.getMethod().getDeclaringType() instanceof TypeString and
ma.getMethod().getName() =
["contains", "startsWith", "matches", "regionMatches", "indexOf", "lastIndexOf"]
}
/**
* Holds if `ma` is a call to a method of `java.nio.file.Path` that checks a partial path match.
*/
private predicate isPathPartialMatch(MethodAccess ma) {
ma.getMethod().getDeclaringType() instanceof TypePath and
ma.getMethod().getName() = "startsWith"
}
private predicate isDisallowedWord(CompileTimeConstantExpr word) {
word.getStringValue().matches(["%WEB-INF%", "%META-INF%", "%..%"])
}
/** A complementary guard that protects against path traversal, by looking for the literal `..`. */
class PathTraversalGuard extends Guard instanceof MethodAccess {
Expr checked;
PathTraversalGuard() {
super.getMethod().getDeclaringType() instanceof TypeString and
super.getMethod().hasName(["contains", "indexOf"]) and
super.getAnArgument().(CompileTimeConstantExpr).getStringValue() = ".."
}
Expr getCheckedExpr() { result = super.getQualifier() }
}
/** A complementary sanitizer that protects against path traversal using path normalization. */
private class PathNormalizeSanitizer extends MethodAccess {
PathNormalizeSanitizer() {
this.getMethod().getDeclaringType().hasQualifiedName("java.nio.file", "Path") and
this.getMethod().hasName("normalize")
}
}
/** A complementary guard that protects against double URL encoding, by looking for the literal `%`. */
private class UrlEncodingGuard extends Guard instanceof MethodAccess {
UrlEncodingGuard() {
super.getMethod().getDeclaringType() instanceof TypeString and
super.getMethod().hasName(["contains", "indexOf"]) and
super.getAnArgument().(CompileTimeConstantExpr).getStringValue() = "%"
}
Expr getCheckedExpr() { result = super.getQualifier() }
}
/** A complementary sanitizer that protects against double URL encoding using URL decoding. */
private class UrlDecodeSanitizer extends MethodAccess {
UrlDecodeSanitizer() {
this.getMethod().getDeclaringType().hasQualifiedName("java.net", "URLDecoder") and
this.getMethod().hasName("decode")
}
}

View File

@@ -0,0 +1,23 @@
edges
| FilePathInjection.java:20:21:20:34 | getPara(...) : String | FilePathInjection.java:25:47:25:59 | finalFilePath |
| FilePathInjection.java:61:50:61:58 | file : File | FilePathInjection.java:66:30:66:33 | file |
| FilePathInjection.java:88:17:88:44 | getParameter(...) : String | FilePathInjection.java:92:24:92:31 | filePath |
| FilePathInjection.java:88:17:88:44 | getParameter(...) : String | FilePathInjection.java:92:24:92:31 | filePath : String |
| FilePathInjection.java:92:15:92:32 | new File(...) : File | FilePathInjection.java:100:19:100:22 | file : File |
| FilePathInjection.java:92:24:92:31 | filePath : String | FilePathInjection.java:92:15:92:32 | new File(...) : File |
| FilePathInjection.java:100:19:100:22 | file : File | FilePathInjection.java:61:50:61:58 | file : File |
nodes
| FilePathInjection.java:20:21:20:34 | getPara(...) : String | semmle.label | getPara(...) : String |
| FilePathInjection.java:25:47:25:59 | finalFilePath | semmle.label | finalFilePath |
| FilePathInjection.java:61:50:61:58 | file : File | semmle.label | file : File |
| FilePathInjection.java:66:30:66:33 | file | semmle.label | file |
| FilePathInjection.java:88:17:88:44 | getParameter(...) : String | semmle.label | getParameter(...) : String |
| FilePathInjection.java:92:15:92:32 | new File(...) : File | semmle.label | new File(...) : File |
| FilePathInjection.java:92:24:92:31 | filePath | semmle.label | filePath |
| FilePathInjection.java:92:24:92:31 | filePath : String | semmle.label | filePath : String |
| FilePathInjection.java:100:19:100:22 | file : File | semmle.label | file : File |
subpaths
#select
| FilePathInjection.java:25:47:25:59 | finalFilePath | FilePathInjection.java:20:21:20:34 | getPara(...) : String | FilePathInjection.java:25:47:25:59 | finalFilePath | External control of file name or path due to $@. | FilePathInjection.java:20:21:20:34 | getPara(...) | user-provided value |
| FilePathInjection.java:66:30:66:33 | file | FilePathInjection.java:88:17:88:44 | getParameter(...) : String | FilePathInjection.java:66:30:66:33 | file | External control of file name or path due to $@. | FilePathInjection.java:88:17:88:44 | getParameter(...) | user-provided value |
| FilePathInjection.java:92:24:92:31 | filePath | FilePathInjection.java:88:17:88:44 | getParameter(...) : String | FilePathInjection.java:92:24:92:31 | filePath | External control of file name or path due to $@. | FilePathInjection.java:88:17:88:44 | getParameter(...) | user-provided value |

View File

@@ -0,0 +1,127 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jfinal.core.Controller;
public class FilePathInjection extends Controller {
private static final String BASE_PATH = "/pages";
// BAD: Upload file to user specified path without validation
public void uploadFile() throws IOException {
String savePath = getPara("dir");
File file = getFile("fileParam").getFile();
String finalFilePath = BASE_PATH + savePath;
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(finalFilePath);
int i = 0;
do {
byte[] buf = new byte[1024];
i = fis.read(buf);
fos.write(buf);
} while (i != -1);
fis.close();
fos.close();
}
// GOOD: Upload file to user specified path with path normalization and validation
public void uploadFile2() throws IOException {
String savePath = getPara("dir");
File file = getFile("fileParam").getFile();
String finalFilePath = BASE_PATH + savePath;
Path path = Paths.get(finalFilePath).normalize();
if (path.startsWith(BASE_PATH)) {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(path.toFile());
int i = 0;
do {
byte[] buf = new byte[1024];
i = fis.read(buf);
fos.write(buf);
} while (i != -1);
fis.close();
fos.close();
}
}
private void readFile(HttpServletResponse resp, File file) {
OutputStream os = null;
FileInputStream fis = null;
try {
os = resp.getOutputStream();
fis = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()];
fis.read(fileContent);
os.write(fileContent);
} catch (Exception e) {
System.err.println("Invalid directory or file " + file.getName());
} finally {
try {
if (os != null)
os.close();
} catch (Exception e2) {
}
try {
if (fis != null)
fis.close();
} catch (Exception e2) {
}
}
}
public void downloadFile() throws FileNotFoundException, IOException {
HttpServletRequest request = getRequest();
String path = request.getParameter("path");
String filePath = BASE_PATH + path;
HttpServletResponse resp = getResponse();
File file = new File(filePath);
if (path != null && file.exists()) {
resp.setHeader("Content-type", "application/force-download");
resp.setHeader("Content-Disposition", "inline;filename=\"" + filePath + "\"");
resp.setHeader("Content-Transfer-Encoding", "Binary");
resp.setHeader("Content-length", "" + file.length());
resp.setHeader("Content-Type", "application/octet-stream");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
readFile(resp, file);
} else {
System.err.println("File does not exist " + path);
}
}
public void downloadFile2() throws FileNotFoundException, IOException {
HttpServletRequest request = getRequest();
String path = request.getParameter("path");
String filePath = BASE_PATH + path;
HttpServletResponse resp = getResponse();
if (!filePath.contains("..") && filePath.startsWith(BASE_PATH)) {
File file = new File(filePath);
if (file.exists()) {
resp.setHeader("Content-type", "application/force-download");
resp.setHeader("Content-Disposition", "inline;filename=\"" + filePath + "\"");
resp.setHeader("Content-Transfer-Encoding", "Binary");
resp.setHeader("Content-length", "" + file.length());
resp.setHeader("Content-Type", "application/octet-stream");
resp.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
readFile(resp, file);
} else {
System.err.println("File does not exist " + path);
}
}
}
}

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-073/FilePathInjection.ql

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jfinal-4.9.15

View File

@@ -0,0 +1,331 @@
package com.jfinal.core;
import java.io.File;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.jfinal.kit.Kv;
import com.jfinal.upload.UploadFile;
public abstract class Controller {
public String getPara(String name) {
return null;
}
public String getPara(String name, String defaultValue) {
return null;
}
public Map<String, String[]> getParaMap() {
return null;
}
public Enumeration<String> getParaNames() {
return null;
}
public String[] getParaValues(String name) {
return null;
}
public Integer[] getParaValuesToInt(String name) {
return null;
}
public Long[] getParaValuesToLong(String name) {
return null;
}
public Enumeration<String> getAttrNames() {
return null;
}
public <T> T getAttr(String name) {
return null;
}
public <T> T getAttr(String name, T defaultValue) {
return null;
}
public String getAttrForStr(String name) {
return null;
}
public Integer getAttrForInt(String name) {
return -1;
}
public String getHeader(String name) {
return null;
}
public Integer getParaToInt(String name) {
return null;
}
public Integer getParaToInt(String name, Integer defaultValue) {
return null;
}
public Long getParaToLong(String name) {
return null;
}
public Long getParaToLong(String name, Long defaultValue) {
return null;
}
public Boolean getParaToBoolean(String name) {
return false;
}
public Boolean getParaToBoolean(String name, Boolean defaultValue) {
return false;
}
public Boolean getParaToBoolean() {
return false;
}
public Boolean getParaToBoolean(int index) {
return false;
}
public Boolean getParaToBoolean(int index, Boolean defaultValue) {
return false;
}
public Date getParaToDate(String name) {
return null;
}
public Date getParaToDate(String name, Date defaultValue) {
return null;
}
public Date getParaToDate() {
return null;
}
public HttpServletRequest getRequest() {
return null;
}
public HttpServletResponse getResponse() {
return null;
}
public HttpSession getSession() {
return null;
}
public HttpSession getSession(boolean create) {
return null;
}
public <T> T getSessionAttr(String key) {
return null;
}
public <T> T getSessionAttr(String key, T defaultValue) {
return null;
}
public String getCookie(String name, String defaultValue) {
return null;
}
public String getCookie(String name) {
return null;
}
public Integer getCookieToInt(String name) {
return null;
}
public Integer getCookieToInt(String name, Integer defaultValue) {
return null;
}
public Long getCookieToLong(String name) {
return null;
}
public Long getCookieToLong(String name, Long defaultValue) {
return null;
}
public Cookie getCookieObject(String name) {
return null;
}
public Cookie[] getCookieObjects() {
return null;
}
public String getPara() {
return null;
}
public String getPara(int index) {
return null;
}
public String getPara(int index, String defaultValue) {
return null;
}
public Integer getParaToInt(int index) {
return null;
}
public Integer getParaToInt(int index, Integer defaultValue) {
return null;
}
public Long getParaToLong(int index) {
return null;
}
public Long getParaToLong(int index, Long defaultValue) {
return null;
}
public Integer getParaToInt() {
return null;
}
public Long getParaToLong() {
return null;
}
public Kv getKv() {
return null;
}
public List<UploadFile> getFiles(String uploadPath, Integer maxPostSize, String encoding) {
return null;
}
public UploadFile getFile(String parameterName, String uploadPath, Integer maxPostSize, String encoding) {
return null;
}
public List<UploadFile> getFiles(String uploadPath, int maxPostSize) {
return null;
}
public UploadFile getFile(String parameterName, String uploadPath, int maxPostSize) {
return null;
}
public List<UploadFile> getFiles(String uploadPath) {
return null;
}
public UploadFile getFile(String parameterName, String uploadPath) {
return null;
}
public List<UploadFile> getFiles() {
return null;
}
public UploadFile getFile() {
return null;
}
public UploadFile getFile(String parameterName) {
return null;
}
public String get(String name) {
return null;
}
public String get(String name, String defaultValue) {
return null;
}
public Integer getInt(String name) {
return -1;
}
public Integer getInt(String name, Integer defaultValue) {
return -1;
}
public Long getLong(String name) {
return null;
}
public Long getLong(String name, Long defaultValue) {
return null;
}
public Boolean getBoolean(String name) {
return false;
}
public Boolean getBoolean(String name, Boolean defaultValue) {
return false;
}
public Date getDate(String name) {
return null;
}
public Date getDate(String name, Date defaultValue) {
return null;
}
public String get(int index) {
return null;
}
public String get(int index, String defaultValue) {
return null;
}
public Integer getInt() {
return -1;
}
public Integer getInt(int index) {
return -1;
}
public Integer getInt(int index, Integer defaultValue) {
return -1;
}
public Long getLong() {
return null;
}
public Long getLong(int index) {
return null;
}
public Long getLong(int index, Long defaultValue) {
return null;
}
public Boolean getBoolean() {
return false;
}
public Boolean getBoolean(int index) {
return false;
}
public Boolean getBoolean(int index, Boolean defaultValue) {
return false;
}
}

View File

@@ -0,0 +1,6 @@
package com.jfinal.kit;
import java.util.HashMap;
public class Kv extends HashMap {
}

View File

@@ -0,0 +1,32 @@
package com.jfinal.upload;
import java.io.File;
public class UploadFile {
public UploadFile(String parameterName, String uploadPath, String filesystemName, String originalFileName, String contentType) {
}
public String getParameterName() {
return null;
}
public String getFileName() {
return null;
}
public String getOriginalFileName() {
return null;
}
public String getContentType() {
return null;
}
public String getUploadPath() {
return null;
}
public File getFile() {
return null;
}
}