Where to put file that a jar needs to load - java

I have a jar that will be connecting to a website for communication using websockets. The website is an SSL site and for that reason I have a .ts the program needs to load file. The following is the java code used to load that .ts file
System.setProperty("javax.net.ssl.trustStore",
"foo.ts");
System.setProperty("javax.net.ssl.trustStorePassword", "password");
and the java program is in a package called foo.web so thus when packed into the jar is in a folder called foo which then has a subfolder called web.
My question is, do I put the foo.ts in the foo/web folder where my classes reside or should I put the foo.ts file at the root of the jar to be loaded with my current code in the program for loading the foo.ts file?

The work around System.setProperty... needing a 'regular' file path, is using mechanism to resolve class resources:
place ts file in your code folder under some package (normal web code not
a library jar code)
in a class from the same package, call:
a
//this will find the file in the package folder
URL cert = this.getClass().getResource("ts");
String path = cert.toString(); //this translate the url to file system location
if (path.startsWith("file:"))
path = path.substring("file:".length()+1,path.length()); //getting rid of file prefix as not needed
System.setProperty("javax.net.ssl.trustStore", path);
If you want to include ts in jar, similar trick, but instead of path (which will not work, read the content and save it to temporary location
in = this.getClass().getResourceAsStream(wsdl);
... save it to tmp location
System.setProperty("javax.net.ssl.trustStore", your tmp location);

I assume that you have unsigned, self generated certificate that you want to use for your ssl connection.
The part that servers the content over ssl, (your tomcat on 443 or apache) needs to know the certificate and its key (configured as in tomcat or apache document).
Your java code that is deployed on that server, does not need to knwo about the certificate or even that is behind ssl.
But the code that wants to connect to such server, lets say web service client will throw exception (and very obscured btw) as it will not recognize the certificate and refuse connecting (unlike the web browser which ofer the dialog that lets you add an exception).
So the client code needs the certificate added to its TrustedStore before oppening connection (the trick with System.property does the job). Thanks to it the client can trust the connection as your remote cert matches the one he already has.
If your client code happens to be running on the same tomcat, it still needs the cert added to the store, as the configuration options for connector at 443 only expose the cert to anyone who can read it, but do not add it to the tomcat's pool of know certificates. To do so you need the -Djava.net.ssl.trustStore=YOUR_TS -Djavax.net.trustStorePassword=PASS options for tomcat starts, or the System.setProperty inside your application code.

The value of the javax.net.ssl.trustStore property is a file path that points to the location of the trust store on disk. If you don't specify a folder, it will assume the current working directory for the program which is most likely where the JVM was invoked from. If you are unsure what your current working directory is, you can get it from the user.dir system property.
System.getProperty("user.dir"));

Related

How to properly package keystore in .jar file

I'm at the final step of developing (and especially deploying) a client server application where I have a secured connection using TLS. I got the keystore and truststore for the client and the server and currently I load them as SystemProperties before creating the SSLSocket / SSLServerSocket like this:
Properties systemProperties = System.getProperties();
systemProperties.put("javax.net.ssl.keyStore", "./auth/labkey.jks");
systemProperties.put("javax.net.ssl.keyStorePassword", "<somepassword>");
systemProperties.put("javax.net.ssl.trustStore", "./auth/labtrust.jks");
systemProperties.put("javax.net.ssl.trustStorePassword", "<somepassword>");
System.setProperties(systemProperties);
This works fine but - as I already thought - doesn't when packaging everything into a .jar file. Currently my project folder consists of the normal src folder in which I keep all the packages with the sourcecode files. The keystore and truststore are kept in a folder called "auth" which is on the same level as the src folder.
I know from previous projects that the relative path changes when packaging additional files into the .jar however the first thing is I don't know how I should properly handle these file to have them packed into the .jar (currently they are only included when I create a package for them in the source folder or declare the auth folder as an additional source folder).
I tried both approaches and after testing a lot of different relative paths (which is the second problem: finding the right relative path) I couldn't figure out how to properly address them.
Any advice or hint would be really appreciated.
EDIT:
After trying out several things in context with suggested ideas I can narrow the problem down to the path to the keystore and truststore file being my actual problem. I'm quite sure if I were able to access it relatively there would be an option to use, however for accessing the files I HAVE to provide a path in any kind, no matter which approach I'm going to use. The fact that I'm not able to get the proper relative path to the file is therefore the main problem which I need to get solved.
So accordingly these questions come to my mind:
How do I correctly add these files to the .jar?
Will I need to make the auth folder a source folder or do I need to put it in a package or is there any need or possibility to configure the files correctly by configuring the build path?
What will then be the relative path to the files?
Quick edit: this has been answered before in previous threads - I'm sure my explanation is sub-par here, but this came up recently for me as well and this was my solution
You may want to use getClass().getClassLoader.getResourceAsStream("filename.properties")
Properties properties = new Properties();
String propertiesFileName = "config.properties";
inputStream = getClass().getClassLoader().getResourceAsStream(propertiesFileName);
if (inputStream != null) {
properties.load(inputStream);
} else {
throw new FileNotFoundException("property file '" + propertiesFileName + "' not found.");
}

Can't get Java Resource file in AWS Lambda

I am trying to configure an SSL connection between PostgreSQL and AWS Lambda. The problem is passing the AWS certificate PEM file to pgjdbc.
I added the PEM file to my resources folder and tried to get it's location with:
Thread.currentThread().getContextClassLoader().getResource("rds-combined-ca-bundle.pem").toString();
And it returns:
file:/var/task/rds-combined-ca-bundle.pem
But if I pass that as the sslrootcert property, I get an exception:
org.postgresql.util.PSQLException: Could not open SSL root certificate file file:/var/task/rds-combined-ca-bundle.pem.
I then decided to run a code that prints all directories and files names from my Lambda, staring with the current folder, and I get the rds-combined-ca-bundle.pem file at the current directory.
What's the correct way to get a PEM file from my resources and pass it to pgjdbc then?
So this won't fix the problem described here, but it will solve my issue at configuring pgjdbc.
If you want to pass a Certificate PEM file to pgjdbc, as a resource file, add the following configuration to your properties file:
sslfactory = org.postgresql.ssl.SingleCertValidatingFactory
sslfactoryarg = classpath:rds-combined-ca-bundle.pem
SingleCertValidatingFactory accepts other kinds of references to the file, as a classhpath, a file path, an environment variable, a system variable or the Certificate text itself. For more information, see the class docs here.

Referencing keystore file for JSSE from Maven jar

I am trying to write a simple client/server application using JSSE for SSL sockets.
I have generated my own 'handmade' certificate with keytool for the server , and I have to set property 'keystore' as follow:
System.setProperty("javax.net.ssl.keyStore","/keystore.ks");
The problem is the following:
As far as I understand, the setProperty wants just the name of the file , not the file itself.
From IDE it works just fine if I use the path to the file (i.e. src/main/resources/keystore.ks , using the standard maven directory structure )
The prpoblem come after I build the JAR with maven. The resource cannot be found.
I understand that resources files are copied in the root of JAR , but I didn't find any method to obtain the right filename to feed to setProperty.
I also tried
String pathKeystore=Server.class.getResource("/keystore.ks").getPath();
and also .toString() .toExternalForm() and so on. But none of it works if later I setProperty with this string.
Looking on other questions I see that the pathname is generally not used for resources, and instead you just read the file , but I need the String in my case.
I don't have a good understanding of what I am doing since I am new to Maven, but basically my question can be summed up as follow:
How to obtain the correct path name of a resource file to be used as a String for setProperty method in a maven-built JAR file?
Thanks in advance to everyone.
EDIT:
I considered also to set the property at runtime :
I launched my jar with
java -Djavax.net.ssl.keyStore=keystore.ks -jar my_jar.jar
I still set the password of this keystore in the code, since I don't have issue with the path with this.
I want to add that I had the same issue on my own client, I have to add the trustStore manually , and I launched it with
java -Djavax.net.ssl.trustStore=jssecacerts -jar my_client_jar.jar
This worked fine, and I guess this is the way that should be done, instead of using the filename.

javax.xml.ws.Service could not read wsdlDocumentationLocation which is declare as URL('file:Authentication.wsdl')

My Java servlet, developed with JDeveloper 11g R2 and deployed on a WebLogic Server 10.3.6, needs to communicate with a specific WebService developed by a tiers company.
The javax.xml.ws.Service is created with wsdlDocumentLocation as a URL ('file:Authentication.wsdl').
Everything works fine on my server where the FireWall is disabled.
But on the customer server, I get the following error:
file:Authentication.wsdl
Jan 22, 2016 9:27:32 AM weblogic.wsee.jaxws.spi.WLSProvider createServiceDelegate WARNING: Could not read WSDL Definition from URL wsdlDocumentLocation: 2 counts of InaccessibleWSDLException.
Jan 22, 2016 9:27:32 AM weblogic.wsee.jaxws.spi.WLSServiceDelegate addWsdlDefinitionFeature SEVERE: Failed to create WsdlDefinitionFeature for wsdl location: file:Authentication.wsdl, error: com.sun.xml.ws.wsdl.parser.InaccessibleWSDLException, message: 2 counts of InaccessibleWSDLException.
I suspect the firewall on the customer server to block the access to the file Authentication.wsdl?
I'm not sure but, for what I understand, using a URL with file: point to a local file accessed by some network protocol? Am I right?
If it's true, can you explain me what type of rules I should set in my firewall (Linux) to give access to this local file?
Does file:Authentication.wsdl means http://localhost:Authentication.wsdl or something like http://localhost/myServletContext/Authentication.wsdl?
I can not figure out what I need to do to solve this issue.
I did futher tests and display informations about the URL objet. For new URL('file:/tmp/Authentication.wsdl'), getPort() returns -1, getHost() returns nothing and getPath() returns /tmp/Authentication.wsdl.
My Authentication.wsdl is inside my jar file which I use in my war file.
“file:Authentication.wsdl” is not a network protocol. It just refers to a plain old file name, on the same system.
It fails because your Authentication.wsdl is not actually a file. It's an entry in a .jar file, which I assume is on the classpath (as all .jar files in a .war file's WEB-INF/lib structure are). For this reason, a file: URL will never work in a production environment. No one distributes Java applications in unarchived form (for a number of good reasons).
An entry which is in the classpath is known as a resource. The correct way to access such data is with the Class.getResource method, which scans the classpath for the requested entry:
URL wsdlLocation = MyServlet.class.getResource("Authentication.wsdl");
Note, however, that this will look for Authentication.wsdl in the same package as your class. If your Authentication.wsdl is in the root of your archive, you could alter the string argument to find it—but you shouldn't. Placing resources in the root of an archive is very much like placing files in the root of the C: drive; it carries a risk of conflict with the multitude of other libraries in the classpath. That's why Class.getResource assumes, by default, that your file is in a directory that matches the Class object's package structure.
Meaning, if your servlet class is in the com.example.myapp package, Authentication.wsdl should be in the .jar file as com/example/myapp/Authentication.wsdl.

Why getClass().getProtectionDomain().getCodeSource().getLocation().getPath() doesn't work in final product after compiled?

Ok, Here is my Web project. I built it in eClipse with the following structure:
workspace3\MyProject\war\images\uploaded
workspace3\MyProject\war\WEB-INF\classes
Ok, I want to store the uploaded images into workspace3\MyProject\war\images\unloaded, so here is the code at service side & it works fine in Eclipse
String absolutePath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
absolutePath=absolutePath.replace("WEB-INF/classes/", "images/uploaded");
File file = File.createTempFile("upload-", "."+extName, new File(absolutePath));
Ok, now I compiled my project & put it into VPS with Tomcat server and it has the following structure
tomcat7\webapps\ROOT\images\uploaded
tomcat7\webapps\ROOT\WEB-INF\classes
However, somehow when run the website via internet, it couldn't find the images\uploaded location.
Did i do anything wrong here?
Why getClass().getProtectionDomain().getCodeSource().getLocation().getPath() doesn't work in final product after compiled?
You should rather use ServletContext#getRealPath(...) to determine the file system path of your web application:
String absolutePath = request.getServletContext().getRealPath("/images/uploaded");
// File uploaded to this directory will be accessible via
// `http://<yourserver>/<web-app>/images/uploaded/`
But be careful! The servlet specification does not guarantee, that getRealPath will return a path to a writable directory. And it may return null in case the virtual path cannot be translated to a real path!
If you want to be sure, that the destination is a writable directory, and you just want to upload files into a temporary directory for processing, consider using the web application's private temp directory:
File tempDir = (File)request.getServletContext().getAttribute(ServletContext.TEMPDIR);
// Files uploaded to that directory will NOT be automatically published to WWW.
Note that this directory is temporary only and may not survive a server restart! So it is not thought for durable persistance.
The most sensible and durable solution is to write the file into a database, or any other repository (e.g. JCR like Jackrabbit), or into a file directory that is NOT controlled by your web server (and is specified from outside, e.g. via system property or in web.xml).

Categories

Resources