Can't get Java Resource file in AWS Lambda - java

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.

Related

Connecting to Astra DB, withCloudSecureConnectBundle() returns java.io.FileNotFoundException

I am trying to connect to Astra DB which requires a path to secure-connect zip.
This line is causing the issue:
.withCloudSecureConnectBundle(Paths.get("E:\\ProjectAndroid\\9_14_2022_2\\RentPK\\app\\src\\main\\res\\secure-connect-rentpk"))
Path.get gives the error.
I wanted to connect Astra DB using secure-connect zip but Paths.get() not working for the given path. Where the path is:
E:\\ProjectAndroid\\9_14_2022_2\\RentPK\\app\\src\\main\\res\\secure-connect-rentpk
It looks like you haven't provided the full name for the secure bundle. In your sample code, you've specified the filename as secure-connect-rentpk which is incorrect.
You need to make sure that you include the .zip suffix in the filename and don't unzip the bundle leaving it intact. For example:
.withCloudSecureConnectBundle(Paths.get("/path/to/secure-connect-db.zip"))
As a side note, you should never include the secure bundle in your source code. You need to place it in a separate location such as a configuration folder for best practice. Cheers!

FileNotFoundException in SpringBoot when running in Docker Container

My Springboot Application is running fine in IDE but when I create fat jar file and run on docker it gives the error. I am connecting my application with firebase so i want to include the serviceAccountKey.json file from the resource folder. The application runs fine in my ide, but while deploying it over the docker container it gives the error of file not found. Though when include the file and print it path it doesn't give any sort of error . But when i give the file path to fileInputStream it produces the error. I have tried multiple ways but nothing seems to work. I'm including the file using classLoader.getResource("filename.json").
I tried to skip the inclusion of file and do it by saving files content in a string and then sending it to stream but this method crashes the server whenever i query firebase.
this is the code where error is occurring. Notice that I'm printing the file path and it gets printed in the output before showing error. I have also tried file.getAbsoluteFile instead of path but doesn't work. Probably I'm doing it wrong or probably i have to mention the path in some other place as well which i don't know about. If anyone has done this before then please help me on this.
File path is getting printed but FileStream can't get it
An alternative to having a credential in a json file that is packaged with the application, would be that you set an environment variable upon starting the application, and instead load the key via application.yml. This way, you don't need to package the secrets into the application jar file.
1. create config class
#Configuration
#ConfigurationProperties(value = "my-custom-config")
public class MyConfig {
private String serviceAccountKey;
// getters/setters etc. if not using lombok
}
2. use above config
in other spring beans by injecting the config class, and retrieve the secret with getter, e.g. config.getServiceAccountKey();
3. Add config to your application.yml file
# application.yml
my-custom-config:
serviceAccountKey: ${ENV_VARIABLE_NAME} # <---- this way you can bind an env variable to your config.
4. Define env variable in container on startup
On instantiating the docker container, provide env option and define an environment variable.
docker run -env ENV_VARIABLE_NAME=<value> ...

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.

Where to put file that a jar needs to load

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"));

configure embedded Tomcat7 to use keystorefile embedded in executable jar

I've managed to configure my embedded tomcat to use a keystorefile and it works when i execute the project from eclipse.
The code is simple:
...
String keystore = new File(MyServer.class.getResource("/keystore").toURI()).toPath().toString();
httpsConnector.setAttribute("keystoreFile",keystore);
...
The file keystore is located in a source directory added to the buildpath.
After exporting the project to an executable jar, i can verify the existence of the keyfile in the root of the jar.
But on executing the jar, i get this error:
Exception in thread "main" java.lang.IllegalArgumentException: URI is not hierarchical
So i asume, that i can not configure the keyfile with httpsConnector.setAttribute("keystoreFile",...). is there another way to configure that? i really dont want to copy the keyfile in a temp dir and reference it from there.
i really dont want to copy the keyfile in a temp dir and reference it from there.
I sympathize, but it looks like you will have to just that. A Java keystore can be loaded from any type of input stream (see Keystore.load) so you would think it would be possible to load your keystore from a resource in the jar file. However if you search the Tomcat 7 source code for the string "ks.load" you will see that it always interprets the keystoreFile attribute as the name of a File and creates a FileInputStream which it then passes the ks.load.
Therefore it will be necessary to create the temp file containing the keystore and pass the location of this file as your keystoreFile attribute.
BTW - if you are not intending to distribute this jar and are willing to keep it private, then your approach of embedding the keystore is probably OK.
However if you are planning on distributing this jar to multiple sites, then the security of every site is based on the same private key. Furthermore, anyone with access to the jar file can probably extract the private key and can then eavesdrop or perhaps man-in-the-middle attack all of your sites.
In general it is better to have an installation process that requires a new private key and certificate to be generated by the administrator of the site (even if it's just a self-signed certificate). That way every key is different and the only way to compromise the site would be to get access to that servers key store and password.
This might be an old post, but I encountered the same problem and didn't found a solution online. So I want to share what I did.
In my case, I needs two ports both with self-signed certificates. Besides the one configured in application.yml, the other port is configured in the main entry.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServletWebServerFactory servletContainer() throws IOException
{
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.addAdditionalTomcatConnectors(additionalConnector());
return tomcat;
}
private Connector additionalConnector() throws IOException
{
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("https");
connector.setPort(8088);
...
URL keystore = new ClassPathResource("keystore.jks").getURL();
connector.setAttribute("keystoreFile", keystore.toExternalForm());
return connector;
}
}
Using URL, both mvn spring-boot:run and run the jar work and can load the keystore without problem.
I was using spring-boot 2.0.1.RELEASE and tomcat 8.5.29

Categories

Resources