JSP: FileReader with relative path throws FileNotFoundException - java

I have some embedded Java code in which I'm trying to load a properties file that is located in the same folder as the JSP file:
Properties titles = new Properties();
titles.load(new FileReader("titles.txt"));
The code above throws a FileNotFoundException.
How exactly does one refer to the 'current folder' in this situation?

Two things:
JSPs should not contain java code. use an mvc framework (spring mvc, stripes etc) as controller and use the JSP as view only. That makes life a lot easier
You are not supposed to access resource files through the file system in a web app, use classloader access as suggested by redlab. The problem is that a web app may or may not be unpacked on the file system, that's up to the servlet container
The main problem I see is that you can't make any valid assumptions as to what the path is, as you don't know where your compiled JSPs are
So: create a controller class, put the properties file in the same folder and load it from the controller class via getClass().getClassLoader().getResourceAsStream("titles.txt");

FileReader requires absolute path, or relative the where the java is run. But for web applications this is usually done via /etc/init.d/tomcat startup and you can't rely on what is the current dir.
You can obtain the absolute path of your application by calling servletContext.getRealPath("/relative/path/to/file.txt")
You can get the relative part of the URL by calling request.getRequestURL().
That said, you'd better use this code in a servlet, not a JSP - JSP is a view technology and logic should not be placed in it.

By using the classloader that loads your class you can get the file easily.
getClass().getClassLoader().getResourceAsStream("titles.txt");
However I don't know if it will work with JSP
You could also use ServletContext.getResourceAsStream(""), but then you have to give the full webcontent-relative path.

Related

Preventing access to WEB-INF from JSP

I am working on some security alerts on one of our servers whereby a 'file download' JSP file is able to let a user download contents of WEB-INF for the web application (Which is located in the root folder of the site). It is a very crudely simple file, written in 2007, that uses java.io.FileInputStream on unsanitised input to return a file to the user.
The alert actually claimed that this was a directory traversal problem, which it is in one way as the following URI would download the web.xml for the user:
http://domain.com/filedownload.jsp?filename=../../WEB-INF/web.xml&filepath=some/directory/
Now obviously the 'directory traversal' part should be corrected by doing user input sanitising (Which this script does not yet do). However, the following URI also delivers the web.xml to the user, but input sanitisation for directory traversal would not help here, unless the sanitisation checks for 'WEB-INF' and other 'illegal' directories...
http://domain.com/filedownload.jsp?filename=web.xml&filepath=WEB-INF/
Is there a standardised way to prevent this in common servlet containers or does this need to be entirely managed by the developer of the code? I noticed that the Java 'normalize()' function would not strip out this directory from the user input.
I tried searching for an answer for this, but all I could find was information about preventing the 'serving' of WEB-INF directly, but nothing about preventing it from being accessed from a JSP file itself.
Thanks,
Tom...
You say the JSP page is using java.io.FileInputStream to read the file. That is a standard Java class that is not aware of the fact that it is running inside a servlet container.
So java.io.FileInputStream will be able to access any file that can be accessed by the user process the servlet container (JVM) is running under. There's nothing you could configure in the servlet container to prevent that.
You might like to make sure that files in other areas of the filesystem completely unrelated to the servlet container can't be accessed, e.g. like "/etc/passwd".
Assuming you're running on Linux, what does this URL do:
http://domain.com/filedownload.jsp?filename=passwd&filepath=/etc/
If it does return the file, you've got a bigger problem! Perhaps the security software (not sure what you're using?) that created the alerts will prevent download. If not, operating system file permissions can help, as long as the web server isn't running under root or other privileged account, but that's a short-term emergency fix only.
So no, there there no standardised way to prevent this in common servlet containers, and yes, it does need to be entirely managed by the developer of the code.
When using java.io.FileInputStream, it's the responsibility of the writer / maintainer of the JSP page to ensure that only valid paths are accessed.

Java: Universally accessing resource files regardless of application server

I'm looking for the 'best practice' way to access resource files (for example a bunch of .xml files) as well as the folder structure in which they reside, regardless of the application server used.
Right now I'm using Wildfly 8 server and I access all src/main/resources/xxxx by getting the application real path then using Paths.get(resourcePath) as well as Files.walk(Paths.get(folderPath)) if I want to access a folder's files.
However, I faced a problem when I tried to deploy to Weblogic 12c, because this app server actually takes everything under WEB-INF/classes and creates a .jar file and adds it to WEB-INF/lib. I can still access singular resources using classLoader.getResource(resourcePath) but for some reason when I try to create a new File(Paths.get(resourcePath) or use Files.walk(Paths.get(folderPath)) it doesn't seem to be working. It throws an exception saying to file doesn't exist which I'm guessing is because it is not accessible since it is packaged inside a jar file.
I could potentially use classLoader.getResource(resourcePath) to access all my resources but unfortunately in my case I cannot know what resources will be available at compile time. I specifically NEED to be able to go through a selected folder's files and subfolders but I haven't found a common way to do it on both app servers, or ALL app servers for that matter.
Bonus points if the solution uses the new File api instead of creating a bunch of FileReaders but I'm ok with that too.
You could place the XML files in a folder /WEB-INF/xml and then use the ServletContext to obtain a File or Path for that location.
Variant 1:
call servletContext.getResourceUrl("/WEB-INF/xml") to obtain a URL and convert this URL to a File or Path. But depending on the server this might return a non-file resource URL, e.g. a jndi:/ url.
Variant 2:
call servletContext.getRealPath("/WEB-INF/xml") to obtain a file string and convert this URL to a File or Path.

Getting the path to current dynamic web project JAVA

How can I access an XML file while my application is already deployed?
I'm running a Dynamic Web Application with several classes and a simple rest service, but I don't have any actual servlets, so accessing the ServletContext is not possible, (as far as I know) so using getRealPath() won't work.
An example:
I have a class DBcon which connects to a database, but has to load the properties from an XML file, which are located at /xml/db/oracle-properties.xml
In a normal Java project you can simply use a file input stream, but it won't work for a dynamic web application.
How can I still load the xml file?
If the file is in the classpath, you can get it as input stream with something like this:
InputStream in = this.getClass().getResourceAsStream("xml/db/oracle-properties.xml");
I figured out by reading this: Where to place and how to read configuration resource files in servlet based application?
I've put the xml files in WEB-INF/classes and then used this code to load it:
InputStream xmlFile = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
prop.loadFromXML(xmlFile);

Add virtual folder to web dynamic project

Right now I am trying to accomplish a project on Eclipse Juno and Tomcat 7 that requires to have a "virtual folder" to hold multimedia files (like images, other sub-pages,etc.). I already have some methods to give out the file path in a URI based syntax (lets say I want to access images in /Content/Image) and I want to map that URI to C:\Users\MyUser\Content\image (I am aware that I am binding the project to Windows systems but I will workaround later on in this issue).
Currently my project is called pj, and Eclipse created a context called pj inside the eclipse's tomcat instance (and thats makes a lot of sense). When i test my project with
> http://localhost:8080/pj
it works fine (and it's supposed to).
But there is a problem here: until now I haven't found a way to create a URI in tomcat to actually go to the Content/Image path to grab content to add to my pages (read somewhere that is unhealthy to keep content on WEB-INF folder, so i'm trying to actually get it done the right way). Also read somewhere that to accomplish this objective, I have to do something like this in the contexts:
<context docbase="d:/images" path="/Content/Images"></context>
Also read there that in tomcat, to resolve URIs you have to use contexts to achieve that goal (giving a bridge between the meaning of he URI and it's location in the file system).
Still, as from tomcat 4 (if not mistaken) it is not supposed to fiddle around server.xml, so in ANOTHER attempt to make this right, i try to actually add a context in META-INF inside context.xml with the code shown before. But there is here ANOTHER problem! It seems that adding the path tag makes tomcat go nuts, as said here: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html .
So I am really in a bind here.... What I want to ask is:
What is the best way to actually add an external folder in a web project to fetch multimedia content and
How it is supposed to make it work inside Eclipse?
PS: I am asking this because in one of my methods inside my project I am using the getLoader method to return the InputStream (java.io InputStream NOT Corba) and it return nulls (which means it doesnt find it).
EDIT: Tried to actually fiddle around server.xml by inserting the conext by hand but didn't work, inserting the relative URI doesn't work on the server (local:8080/Content/Image with valid files inside) or going inside my main project and do getstream doesnt work too
After some fiddling around, tweaking, etc. I came up with a workaround for this situation. Like I stated, it IS possible to actually have an outside folder hold all the multimedia and/or pages as you wish. One of the references to that solution is here: http://harkiran-howtos.blogspot.pt/2009/08/map-external-directory-into-your.html .
Still, for some reason, this is not quite possible to make it work inside Eclipse (or I have failed something and wasn´t unable to make it work). But there is an alternate solution for this. It is also feasible to actually have a folder for that purpose INSIDE the web app but OUTSIDE the WEB-INF and META-INF folder. In other words, a folder that is located in the ROOT of the web app.To access those files in that folder you can use something called ServletContext. That context has actually inside all possible references to the folder structure of your web app. To access those files with the context give, you have to use getResourceAsStream from the Servlet context (or use getRealPath if it is necesary and/or you can guarantee that the web app is exploded inside Tomcat). So in other words, to access folders inside the web app but outside the WEB-INF and META-INF you have to use ServletContext and their given methods to get files/streams.
PS: Ty wds for pointing out ServletContext
I made the harkiran's solution work but it's not very good solution.
People discourage use of getRealPath. Mapping external folder is good thing to do for many reasons.
But to do it in Eclipse, you need to go to deployment folder.
In my case it's hidden folder inside Eclipse workspace.
workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/
Inside that folder you shoud make directory structure and file from harkiran's solution. I works until you delete and recreate server in Eclipse.
After that you need to make it again.

What is the best place to store a configuration file in a Java web application (WAR)?

I create a web application (WAR) and deploy it on Tomcat. In the webapp there is a page with a form where an administrator can enter some configuration data. I don't want to store this data in an DBMS, but just in an XML file on the file system. Where to put it?
I would like to put the file somewhere in the directory tree where the application itself is deployed. Should my configuration file be in the WEB-INF directory? Or put it somewhere else?
And what is the Java code to use in a servlet to find the absolute path of the directory? Or can it be accessed with a relative path?
What we do is to put it in a separate directory on the server (you could use something like /config, /opt/config, /root/config, /home/username/config, or anything you want). When our servlets start up, they read the XML file, get a few things out of it (most importantly DB connection information), and that's it.
I asked about why we did this once.
It would be nice to store everything in the DB, but obviously you can't store DB connection information in the DB.
You could hardcode things in the code, but that's ugly for many reasons. If the info ever has to change you have to rebuild the code and redeploy. If someone gets a copy of your code or your WAR file they would then get that information.
Putting things in the WAR file seems nice, but if you want to change things much it could be a bad idea. The problem is that if you have to change the information, then next time you redeploy it will overwrite the file so anything you didn't remember to change in the version getting built into the WAR gets forgotten.
The file in a special place on the file system thing works quite well for us. It doesn't have any big downsides. You know where it is, it's stored seperatly, makes deploying to multiple machines easy if they all need different config values (since it's not part of the WAR).
The only other solution I can think of that would work well would be keeping everything in the DB except the DB login info. That would come from Java system properties that are retrieved through the JVM. This the Preferences API thing mentioned by Hans Doggen above. I don't think it was around when our application was first developed, if it was it wasn't used.
As for the path for accessing the configuration file, it's just a file on the filesystem. You don't need to worry about the web path. So when your servlet starts up it just opens the file at "/config/myapp/config.xml" (or whatever) and it will find the right thing. Just hardcodeing the path in for this one seems pretty harmless to me.
WEB-INF is a good place to put your config file. Here's some code to get the absolute path of the directory from a servlet.
public void init(ServletConfig servletConfig) throws ServletException{
super.init(servletConfig);
String path = servletConfig.getServletContext().getRealPath("/WEB-INF")
Putting it in WEB-INF will hide the XML file from users who try to access it directly through a URL, so yes, I'd say put it in WEB-INF.
I would not store it in the application folder, because that would override the configuration with a new deployment of the application.
I suggest you have a look at the Preferences API, or write something in the users folder (the user that is running Tomcat).
The answer to this depends on how you intend to read and write that config file.
For example, the Spring framework gives you the ability to use XML configuration files (or Java property files); these can be stored in your classpath (e.g., in the WEB-INF directory), anywhere else on the filesystem, or even in memory. If you were to use Spring for this, then the easiest place to store the config file is in your WEB-INF directory, and then use Spring's ClassPathXmlApplicationContext class to access your configuration file.
But again, it all depends on how you plan to access that file.
If it is your custom config WEB-INF is a good place for it. But some libraries may require configs to reside in WEB-INF/classes.

Categories

Resources