spring boot read property value from file content (not property file) - spring-boot

Is there a way to inject the value of a property from file content?
In my case i want to read a public certificate:
#ConstructorBinding
#ConfigurationProperties(prefix = "certificate")
#Value
public class Certificate {
String publicKey;
}
The certificate is in a file with content like
-----BEGIN CERTIFICATE-----
MIIC3DCCAcSgAwIBAgIGAYYWvEf6MA0GCSqGSIb3DQEBCwUAMC8xLTArBgNVBAMM
JDhjOGVmNjQxLTEwMGEtNDUxMi1iOTFhLWM3Mzc5NDcwMTdjMzAeFw0yMzAyMDMx
...
4/eJiZvtUhlPTZAeBCbmwHhLFufMRrYtOje/JLDcXFUhF4Ypb6BITbbWijJ7oMqP
1Amyt3eKiVhFdIVk1U4gp19wda4oeKP+5gaPTvAlYrN+EWdC1lUDRBipcM5zioFk
CwELjzRA2Dzg059g93NN7Q==
-----END CERTIFICATE-----
Currently i have 2 ways to load this as property:
load it in env variable with shell CERTIFICATE_PUBLIC_KEY="$(cat ./certs/device-cert.pem)" - need to run before
change the file to a property file beginning with certificate.publicKey=
and adding "\n" at every line end and adding it as additional property source
Is there a way to load the file content directly into a property on start?
At the moment i don't want to loose the Spring Boot Property feature - because it is really flexible.
If not possible i can of course just load the file and use its content.

It is possible with Spring. You can add the following option to your application properties file:
spring:
config:
import: configtree:/specify_the_path_where_your_file_is_located/
Then you should put your public key file to that location and give a name to this file according to your desired configuration properties:
certificate.publicKey
And you're done here! During application startup the content of that file will be injected to that property and will be both accesible from your configuration properties or from Environment bean

Related

How to get Env specific yaml file inside java class in Mule 4

Hi I Have enviornment specific yaml files in my Mule Application . I need to read these file in my Java Class . My Yaml File name will be formed as
properties/${mule.env}/config-${mule.env}.yaml
So for each env it will load speicfic file. I need to get the respective env file in my java class . How i can do that . I tried like below in Java Class but its coming as null
#Value("${rixml.VersionID}")
private String version;
You can form the YAML filepath in your mule flow and then pass it as an argument to your java class.In your java class you can read the YAML file(from the file path passed to it), parse it and extract the value that you want.

Add SSL keystore file to java trusted store for HTTP Client request on PCF (Cloud Foundry)

In my spring boot application I making a https(secure) request. For that I need pass flowing argument as JVM argument.
javax.net.ssl.trustStore
javax.net.ssl.trustStorePassword
Eg :
-Djavax.net.ssl.trustStore=~/home/dinusha/keystore.jks -Djavax.net.ssl.trustStorePassword=pass
In PCF (Cloud Foundry) I can not copy keystore.jks file to PCF. So how can I pass this values on PCF
You have to bundle the keystore.jks file with application. Please find the step bellow.
Put your keystore.jks file into you application resources(src/main/resources) folder.
Add the keystore.jks path and it's password in the application.properties
client.ssl.trust-store = keystore.jks
client.ssl.trust-password = pass
Now get the property value form application.properties
#value("${client.ssl.trust-password}")
private String trustPassword
#value("${client.ssl.trust-store}")
private String trustStore
Now initialize flowing properties
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword",trustPassword);
Finaly push to PCF
Best to refer and store Keystore.jks and trustStrore.jks is to outsiode your application (WAR , JAR , EAR).
And yes , for request you donot neend ketstore instead you require truststore.jks.
You can store it in GIT or some othe Repo location and point to that location from your application via CloundFoundry.
Put your keystore.jks file into you application resources(src/main/resources) folder.
Add the Truststore.jks path and it's password in the application.properties
*client.ssl.trust-store = keystore.jks
client.ssl.trust-password = pass*
Now get the property value form application.properties
#value("${client.ssl.trust-password}")
private String trustPassword
#value("${client.ssl.trust-store}")
private String trustStore
Put the location with protocol details in manifest file like below :
env:
loglevel: DEBUG,APP
JAVA_OPTS: -XX:+UseConcMarkSweepGC
TRUSTSTORE_LOCATION: https://XXXX:yyyyyy#svninst1.uk.fid-intl.com:18080/svn/TAPP100367DC_API/trunk/dc-Member-Api/dc-Member-Api-web/src/main/resources/cacerts.jks
and get it like:
#value("${client.ssl.trust-password}")
private String trustPassword
#value("${TRUSTSTORE_LOCATION}")
private String trustStore

How to externalize configuration in Spring Boot using profiles?

I have an application where I would like to change a datasource password that is stored in a application.yml file. The password in the YML file is stored such as this:
----
spring:
profiles: production
datasource:
password: prodpassword
Note: I also have profiles for development and stage.
The password prop is set on a class using ConfigurationProperties such as follows:
#Component
#ConfigurationProperties(prefix="datasource")
public class DataSourceConnector {
private password;
public void setPassword(String password) {
this.password = password;
}
Now, I try to override the prodpassword with prodpa$$word via a command line arg but it doesn't work:
java -Dspring.profiles.active=production -jar /usr/share/myapp/myapp-1.0.jar --datasource.password='prodpa$$word'
I also tried creating an identical (except the new password) application.yml file outside of the jar. That doesn't work either.
java -Dspring.profiles.active=production -jar /usr/share/myapp/myapp-1.0.jar --spring.config.location=/usr/share/myapp/
Note: I left out the file name in the location param due to this note from http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config-profile-specific-properties:
If you have specified any files in spring.config.location, profile-specific variants of those files will not be considered. Use directories inspring.config.location if you also want to also use profile-specific properties.
How can I override datasource.password within the application.yml of the jar?
Edit:
The application is being started / stopped using supervisorctl.
After changing the config file that contains the java command, supervisorctl must reread the change:
supervisorctl reread
Next, activate the changes with:
supervisorctl update

How to get Relative Path in Spring web project

I am creating a spring web project where i am uploading a csv file and saving it to database. I need to keep the file in the relative path of the project so that it can be accessed through the url.for example: localhost:port/project_name/file_name
But I am getting the absolute path everytime using servlet context or URL.
Please help me out to get the relative path in spring controller.
You can save the file wherever you want. I particularly create a folder in the tomcat's directory and access it through the Java System Property System.getProperty("catalina.base");
Then to the url you can choose one of these possibilities:
Create a controller that serves the file.
Declare an Context in tomcat: option1 or option2
For example, I saved the file in:
System.getProperty("catalina.base")+File.separator+"mydata"+File.separator+filename;
I can create the controller:
#Controller
public class MyDataController {
#RequestMapping("/mydata/{filename}")
public String helloWorld(#PathVariable("filename") String filename) {
String path = System.getProperty("catalina.base")+File.separator+"mydata"+File.separator+filename;
return new FileSystemResource(new File(path));
}
}
or declare a context in tomcat create the file: [tomcat6directory]/conf/Catalina/localhost/appcontext#mydata.xml containing
<Context antiResourceLocking="false" privileged="true" path="/mydata" docBase="${catalina.base}/mydata" />

org.jasypt.exceptions.EncryptionOperationNotPossibleException

I am using Jasypt-1.9.0 with Spring 3.1 and Hibernate 4.0.1. I have a requirement in my application to connect to database whose password(root) is stored in the encrypted form in the property file within the application.
I looked online and found the way with following links:
http://www.jasypt.org/spring31.html
http://www.jasypt.org/hibernate.html
http://www.jasypt.org/encrypting-configuration.html
I have done the following steps and configuration for my requirement:
Added jasypt-1.9.0 and jasypt-hibernate4-1.9.0 in build path.
Added following in my dispatcher-servlet file:
< bean id="propertyConfigurer"
class="org.jasypt.spring31.properties.EncryptablePropertyPlaceholderConfigurer">
< constructor-arg ref="configurationEncryptor" />
< property name="locations">
< list>
< value>classpath:database.properties< /value>
< /list>
< /property>
< /bean>
< bean id="configurationEncryptor"
class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
< property name="config" ref="environmentVariablesConfiguration" />
< /bean>
< bean id="environmentVariablesConfiguration"
class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
< property name="algorithm" value="PBEWithMD5AndDES" />
< property name="passwordEnvName" value="APP_ENCRYPTION_PASSWORD" />
</bean>
Using CLI tool of Jasypt 1.9.0, I have generated the password
below(attached snapshot of CLI)
- Added a new Environment Varibale as APP_ENCRYPTION_PASSWORD with value as root
Added the encrypted password in database.properties file
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/db1
db.username=root
db.password=ENC(bmfeQmgP/hJrh+mj6NANKA==)
Now, if I run my application, the following exception appears:
org.jasypt.exceptions.EncryptionOperationNotPossibleException
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.decrypt(StandardPBEByteEncryptor.java:981)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:725)
at org.jasypt.properties.PropertyValueEncryptionUtils.decrypt(PropertyValueEncryptionUtils.java:72)
The question is most probably out of date, but for future seekers...
EncryptionOperationNotPossibleException is a general exception thrown by jasypt to mask other possible exceptions. This exception can occur when:
your jdk does not have the JCE unlimited strenght installed (most common case)
you had some data in the database that was encrypted before with other password
you had some data in database that were not encrypted before and you added encryption to some field
jasypt failed to decrypt the encrypted value from db because of some strange corruption of data
many many others, you just need to debug to find out the real cause..
If you don't specifiy all the params during encryption, Jasypt will use default values. Make sure to use those exact default values during decryption. Otherwise you may have troubles...
This work for me:
mvn jasypt:encrypt -Djasypt.encryptor.password='secret' \
-Djasypt.encryptor.algorithm=PBEWITHHMACSHA512ANDAES_256 \
-Djasypt.encryptor.iv-generator-classname=org.jasypt.iv.RandomIvGenerator \
-Djasypt.encryptor.salt-generator-classname=org.jasypt.salt.RandomSaltGenerator \
-Djasypt.encryptor.key-obtention-iterations=1000 \
-Djasypt.plugin.path='file:application.yml'
mvn jasypt:decrypt -Djasypt.encryptor.password='secret' \
-Djasypt.encryptor.algorithm=PBEWITHHMACSHA512ANDAES_256 \
-Djasypt.encryptor.iv-generator-classname=org.jasypt.iv.RandomIvGenerator \
-Djasypt.encryptor.salt-generator-classname=org.jasypt.salt.RandomSaltGenerator \
-Djasypt.encryptor.key-obtention-iterations=1000 \
-Djasypt.plugin.path='file:application.yml'
I also experienced similar issue when encrypting property file values. I encrypted values in my local Windows machine and tried to deploy in Linux box but JRE versions were different, therefore encrypted values could not be decrypted. But I encrypted the values in Linux machine and decryption was successful.
I had a similar issue, but I realize when using the CLI tool and trying to decrypt the password you don't have to include the algorithm property and the password property needs to match the one used in the CLI Tool.
In their http://www.jasypt.org/encrypting-configuration.html
their example looks like this, but this doesn't work.
encryptor.setPassword("jasypt"); // could be got from web, env variable...
encryptor.setAlgorithm("PBEWithHMACSHA512AndAES_256");
encryptor.setIvGenerator(new RandomIvGenerator());
Solution:
encryptor.setPassword("MYPAS_WORD"); // Like in the CLI Tool
encryptor.setAlgorithm("PBEWithHMACSHA512AndAES_256"); //Remove this
encryptor.setIvGenerator(new RandomIvGenerator()); //Remove this as well
It'll work fine.
In your case you can remove the algorithm property and passwordEvnName needs to match the one used in CLI Tool.
Remove all above XML configuration and add the following bean to your configuration class:
#Bean public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder =
DataSourceBuilder.create();
dataSourceBuilder.url(dbUrl);
dataSourceBuilder.username(username);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
Add values from properties like
#Value("${db.driverclassname}")
private String dbDriverClassName;
#Value("${db.url}")
private String dbUrl;
#Value("${db.username}")
private String dbUsername;
#Value("${db.password}")
private String dbPassword;
And pass these values above the data source.
Configure your encryption key in properties file like#
db.driverclassname=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/contactsdb
db.username=contactsuser
db.password=ENC(XcBjfjDDjxeyFBoaEPhG14wEzc6Ja+Xx
+hNPrJyQT888=
Don't create your encrypted key using cmd and jaspyt jar I will share the link for creating encryption key with your secret key:
Jasypt Online Encryption and Decryption
Add jaspyat dependency as per your version.
If you have to run on a server and if you are facing issues like password encryption not matches or not possible, then add one more bean of jdbc template:
#Bean
public JdbcTemplate jdbcTemplate(DataSource
dataSourcee)
{
return new JdbcTemplate(dataSource);
}
It works fine and no issues found.
Create the key using that tool. Because I have tried many times using jaspyt command line but the encryption is wrong and it is not supported. You can cross-check key generated using the above tool with the secret key.

Resources