Spring cloud loading keystore from classpath vs file - spring

I have a spring cloud config server that uses keystore to decrypt values from git server. If I reference the keystore using file path, it works as expected and decrypts the {cipher} values. However, if I try to load the keystore from classpath it stops working with this error :
CipherEnvironmentEncryptor.decrypt - Cannot decrypt key: username (class java.lang.IllegalStateException: Cannot load keys from store: class path resource [mykey.p12])
Im setting the encrypt properties on the class instead of yaml since I need to lookup different passwords from external vault system for dev/prod keystores.
I can also see p.12 file under target/classes after the build, so it is not filtered out during the build. Not sure what I'm missing.
SpringApplication sa = new SpringApplication(Myclass.class);
Properties springProperties = new Properties();
springProperties.setProperty("encrypt.enabled", "true");
springProperties.setProperty("encrypt.key-store.location", "file:///Users/user/IdeaProjects/project/src/main/resources/configuration/mykey.p12"); //working fine
springProperties.setProperty("encrypt.key-store.location", "classpath:/configuration/mykey.p12"); //does not work
springProperties.setProperty("encrypt.key-store.type", "PKCS12");
springProperties.setProperty("encrypt.key-store.password", "password");
springProperties.setProperty("encrypt.key-store.secret", "password");
springProperties.setProperty("encrypt.key-store.alias", "vault");
sa.setDefaultProperties(springProperties);
sa.run(args);
Using
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.2.0.RELEASE</version>
<name>spring-cloud-config-server</name>

My issue was actually related to this : generated certificate stops working when moved to resources folder
I had maven filtering configuration on the resources which was corrupting the final p12 file. For now I just moved files that need filtering to another resource directory and it works.
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/resources-filtered</directory>
<filtering>true</filtering>
<includes>
<include>*.yml</include>
<include>logback.xml</include>
</includes>
</resource>
</resources>

Related

"Unit testing" a Maven build

I have a complex Maven build, and I would like to have some automated check that the JAR files and POM files produced by the build actually contain what I expect them to contain.
For instance, I would like to check for the presence of an Automatic-Module-Name entry in the manifest file. It's a multi-release JAR, so I would like to check that the proper class files exist inside of META-INF/versions. I'm going to publish to Maven Central, so I'd also like to check that the produced pom file contains the dependencies the project needs, but that the produced pom file for the fat jar that I also publish, doesn't contain these dependencies.
Basically, I'd like to unit test my build :).
Unfortunately, it's hard to google for this, because of the words I would use to describe this ("test", "verify") already have very specific different meanings in Maven.
Is there a nice way to do this? I would prefer a Maven plugin, since I'm obviously already using that, but I'm open to other things too.
I ended up, as #khmarbaise suggested in the comments, creating a new Maven submodule. In its pom I used the copy-rename-maven-plugin to copy over the files I actually want to check, like this:
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>${version.copy-rename-maven-plugin}</version>
<executions>
<execution>
<id>copy-artifacts</id>
<phase>compile</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<sourceFile>${project.basedir}../core/target/.flattened-pom.xml</sourceFile>
<destinationFile>${project.basedir}/src/test/resources/flattened.pom</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}../core/target/myArtifactId-${project.version}.jar</sourceFile>
<destinationFile>${project.basedir}/src/test/resources/myArtifactId.jar</destinationFile>
</fileSet>
<!-- more fileSets here -->
</fileSets>
</configuration>
</execution>
</executions>
</plugin>
Then I was able to read the pom file and do assertions on it. I ended up using Java's built-in XPath API, but you can use whatever.
I was also able to read the JAR file by turning it into a NIO FileSystem:
var filename = "myArtifactId.jar"; // or "flattened.pom"
var file = getClass().getClassLoader().getResource(filename);
var uri = URI.create("jar:" + file.toURI().toString());
FileSystem fs = FileSystems.newFileSystem(uri, Map.of());
You can get a list of files:
var path = fs.getPath("/");
Set<String> filenames = StreamSupport
.stream(walk.spliterator(), false)
.map(Path::toString)
.collect(Collectors.toSet());
Or read the content of a file:
var path = fs.getPath("/META-INF/MANIFEST.MF");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
String content = out.toString();
assertTrue(content.contains("Multi-Release: true"));
var path = fs.getPath("/com/example/MyClass.class");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
byte[] content = out.toByteArray();
var actualVersion = content[7]; // the major version of the class file is at this location
assertEquals(52, actualVersion); // 52 = Java 8
(Note that for this answer, I didn't bother to handle exception or close resources; you'll have to do that yourself.)

Concat messages.properties with maven

We have some default message files and we want to be able to customize them by maven profiles.
Therefore we configured two resource entries
<resource>
<directory>${basedir}/resources</directory>
<filtering>true</filtering>
</resource>
<resource>
<directory>${basedir}/profiles/${additionalWebcontent}/java</directory>
<filtering>true</filtering>
</resource>
currently the files from ${basedir}/resources are overwritten by files from ${basedir}/profiles/${additionalWebcontent}/java.
Is it possible to append the content from the files from ${basedir}/profiles/${additionalWebcontent}/java to the content of the files from ${basedir}/resources ?
An example content would be
${basedir}/resources/messages/messages.properties
greeting=Hello World!
logout=Logout
login=Logout
${basedir}/profiles/${additionalWebcontent}/java/messages/messages.properties
greeting=Hello Folks!
Expected Result:
${project.build.directory}/classes/messages/messages.properties
greeting=Hello World!
logout=Logout
login=Logout
greeting=Hello Folks!

Why does Maven include change the structure of my required files

I want to include the directory "dirA" into my .jar
The structure is the following
-mvnModule
-dirA
-dirB
someFiles
-dirC
someFiles
-src
.......
When I do this:
<resources>
<resource>
<directory>dirA/*</directory>
</resource>
</resources>
Why is it that if I investigate the .jar-File, all Files are just under the root (mvnModule). Maven removes my structure, which leads to FileNotFoundExcpetions at runtime. I do not want to change all the paths in the code...is there a way to include it with the correct/original structure?

save user status in maven project

I am writing a javaFX project with netbeans IDE and maven.
I am saving user edits in a property file and i loading it when the application start up and i want to update it when application shuts down to reuse it next time.
So I am reading the property file as below:
public static Properties propConfig = new Properties();
InputStream input;
input = Config.class.getClassLoader().getResourceAsStream("config/displayConfig.properties");
propConfig.load(input);
which works fine..
but i don't know how to update the property file :( as
output = new FileOutputStream( new File(Config.class.getClassLoader().getResource("config/displayConfig.properties").toURI()) );
is not working since it reads the resource file from jar
jar:file:/D:/freelance%20projects/01%20school%20tool%20bar/mavenprojectFX/target/racer40-1.0-SNAPSHOT.jar!/config/displayConfig.properties
Normally it's not recommended to update files in JARs.
Use local files instead, e.g.:
Path userDirPath = Paths.get(System.getProperty("user.home"), ".<myAppSymbolicName>", "<myAppVersion>");
Path configDirPath = userDirPath.resolve("config");
Path displayConfigFilePath = configDirPath.resolve("displayConfig.properties");
// read file
well i have done a workaround, since I can only read files from jar i have defined a new properties file and i have defined the configuration path in it.
i have modified resources in POM.xml to set filtering true
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
i have placed the path property file in "src/main/resources/config" folder
the path file contains
Path=${project.build.directory}
and i am reading it as the following
InputStream pathStream
= Config.class.getClassLoader().getResourceAsStream("config/path.properties");
Properties pathProperties = new Properties();
pathProperties.load(pathStream);
path = pathProperties.get("Path").toString().replace("target", "");
System.out.println(pathProperties.get("Path"));
pathStream.close();
then i am using 'path' variable as the following
OutputStream output = new FileOutputStream(new File(path + displayConfig.properties"));
so I am now putting the configuration file "displayConfig.properties" in the same path of jar.

Cannot load config from custom yml file in spring boot application

I am loading the custom configuration from application.yml in my spring boot service.
I have annotated by bean class as below,
#Component
#ConfigurationProperties("app")
public class ContinentConfig {
private Map<String, List<Country>> continents = new HashMap<String, List<Country>>();
//get/set/tostring methods
}
My custom class Country includes 2 fields,
public class Country {
String name;
String capital;
//get/set/tostring methods
}
In application.yml I have as below,
app:
continents:
Europe:
- name: France
capital: Paris
Asia:
- name: China
capital: Beijing
With the above setup, I am able to load the config from application.yml.
I now want to extract the config to a separate continentconfig.yml in the same src/main/resources folder. So, I moved the custom config to continentconfig.yml leaving other properties like server.port in application.yml.
The continentconfig.yml has the same content as I had earlier in application.yml.
I also added the below annotations to the ContinentConfig Class,
#Component
#ConfigurationProperties("app")
#EnableConfigurationProperties
#PropertySource(value="classpath:continentconfig.yml")
public class ContinentConfig {
}
After this change, I see the config is not getting loaded from continentconfig.yml to ContinentConfig bean.
Can someone please help in resolving the issue.
The short answer you can't do that and you should use the property file.
24.6.4 YAML shortcomings
YAML files can’t be loaded via the #PropertySource annotation. So in
the case that you need to load values that way, you need to use a
properties file.
You can create your initializer and use the YamlPropertySourceLoader.
I believe by externalizing you mean using a property file to load the configuration from a file configured in github/or other such hosting repos? You could very well do that by using bootstrap.yml. This loads all the configurations from an external file and also allows the provision to override them using the local application.properties/application.yml
spring:
application:
name:
cloud :
config :
uri :
Also make sure that you have spring cloud in your pom to resolve this just in case
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
Just incase if your local yml property files are not loaded in your classpath, then add the following
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.yml</include>
<include>**/*.jks</include>
</includes>
</resource>
</resources>
Note: It is preferred to have the YamlPropertySourceLoader to load your config file to your classpath and on top of that you could use the above config

Resources