Skip to content

Commit 295bd3a

Browse files
authored
feat: handle profile and log4j -> logback (#62)
* feat: use spring profile and logback * fix: copy files from jar = boom
1 parent d5dde79 commit 295bd3a

File tree

9 files changed

+129
-167
lines changed

9 files changed

+129
-167
lines changed

Dockerfile

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
FROM tomcat:9-jre17-temurin
1+
FROM gitlab-registry.insee.fr/kubernetes/images/run/java:21.0.8_9-jre-jammy-rootless
22

3-
# Create a non-root user and group
4-
5-
RUN rm -rf "$CATALINA_HOME"/webapps/*
6-
COPY sabdatab.properties log4j2.xml $CATALINA_HOME/webapps/
7-
COPY target/*.war $CATALINA_HOME/webapps/ROOT.war
3+
WORKDIR /opt/app/
4+
COPY ./target/*.jar /opt/app/app.jar
85

96
# Setup a non-root user context (security)
10-
RUN addgroup -g 1000 tomcatgroup; \
11-
adduser -D -s / -u 1000 tomcatuser -G tomcatgroup; \
12-
chown -R tomcat:tomcat "$CATALINA_HOME"
7+
RUN addgroup -g 1000 tomcatgroup
8+
RUN adduser -D -s / -u 1000 tomcatuser -G tomcatgroup
9+
RUN mkdir /opt/app/temp-files
10+
RUN chown -R 1000:1000 /opt/app
1311

1412
USER 1000
1513

16-
# Start Tomcat
17-
CMD ["catalina.sh", "run"]
14+
ENTRYPOINT ["java", "-jar", "/opt/app/app.jar"]

log4j2.xml

Lines changed: 0 additions & 37 deletions
This file was deleted.

pom.xml

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@
77
<parent>
88
<groupId>org.springframework.boot</groupId>
99
<artifactId>spring-boot-starter-parent</artifactId>
10-
<version>3.5.5</version>
10+
<version>3.5.6</version>
1111
<relativePath/> <!-- Use default parent from central repo -->
1212
</parent>
1313

1414
<groupId>fr.insee</groupId>
1515
<artifactId>sabdatab</artifactId>
16-
<packaging>war</packaging>
17-
<version>4.1.1</version>
16+
<packaging>jar</packaging>
17+
<version>4.1.2</version>
1818
<name>Sabiane Data</name>
1919

2020
<properties>
2121
<java.version>17</java.version>
22-
<final.war.name>sabdatab</final.war.name>
22+
<final.jar.name>sabdatab</final.jar.name>
2323
<springdoc-openapi-ui.version>1.7.0</springdoc-openapi-ui.version>
2424
<saxon.version>12.5</saxon.version>
2525
<commons-io.version>2.18.0</commons-io.version>
@@ -71,22 +71,6 @@
7171
<optional>true</optional>
7272
</dependency>
7373

74-
<!-- log4j -->
75-
<dependency>
76-
<groupId>org.springframework.boot</groupId>
77-
<artifactId>spring-boot-starter</artifactId>
78-
<exclusions>
79-
<exclusion>
80-
<groupId>org.springframework.boot</groupId>
81-
<artifactId>spring-boot-starter-logging</artifactId>
82-
</exclusion>
83-
</exclusions>
84-
</dependency>
85-
<dependency>
86-
<groupId>org.springframework.boot</groupId>
87-
<artifactId>spring-boot-starter-log4j2</artifactId>
88-
</dependency>
89-
9074
<dependency>
9175
<groupId>commons-io</groupId>
9276
<artifactId>commons-io</artifactId>
@@ -103,7 +87,7 @@
10387
</dependencies>
10488

10589
<build>
106-
<finalName>${final.war.name}</finalName>
90+
<finalName>${final.jar.name}</finalName>
10791
<resources>
10892
<resource>
10993
<filtering>true</filtering>
@@ -123,14 +107,13 @@
123107
<target>${java.version}</target>
124108
</configuration>
125109
</plugin>
126-
<plugin>
127-
<groupId>org.apache.maven.plugins</groupId>
128-
<artifactId>maven-war-plugin</artifactId>
129-
<version>3.4.0</version> <!-- Update this version -->
130-
</plugin>
110+
131111
<plugin>
132112
<groupId>org.springframework.boot</groupId>
133113
<artifactId>spring-boot-maven-plugin</artifactId>
114+
<configuration>
115+
<mainClass>fr.insee.sabianedata.ws.AppWS</mainClass>
116+
</configuration>
134117
<executions>
135118
<execution>
136119
<id>repackage</id>

sabdatab.properties

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/main/java/fr/insee/sabianedata/ws/AppWS.java

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@
88
import lombok.extern.slf4j.Slf4j;
99
import org.springframework.boot.SpringApplication;
1010
import org.springframework.boot.autoconfigure.SpringBootApplication;
11-
import org.springframework.boot.builder.SpringApplicationBuilder;
1211
import org.springframework.boot.context.event.ApplicationReadyEvent;
1312
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
14-
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
1513
import org.springframework.context.annotation.Bean;
1614
import org.springframework.context.event.ContextRefreshedEvent;
1715
import org.springframework.context.event.EventListener;
@@ -25,27 +23,13 @@
2523
@SpringBootApplication
2624
@ConfigurationPropertiesScan
2725
@Slf4j
28-
public class AppWS extends SpringBootServletInitializer {
26+
public class AppWS {
2927

30-
public static final String APP_NAME = "sabdatab";
3128

3229
public static void main(String[] args) {
33-
System.setProperty("spring.config.name", APP_NAME);
3430
SpringApplication.run(AppWS.class, args);
3531
}
3632

37-
@Override
38-
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
39-
System.setProperty("spring.config.name", APP_NAME);
40-
setProperty();
41-
return application.sources(AppWS.class);
42-
}
43-
44-
public static void setProperty() {
45-
System.setProperty("spring.config.location",
46-
"classpath:/," + "file:///${catalina.base}/webapps/" + APP_NAME + ".properties");
47-
}
48-
4933
@EventListener
5034
public void handleContextRefresh(ContextRefreshedEvent event) {
5135
final Environment env = event.getApplicationContext().getEnvironment();
@@ -65,7 +49,7 @@ public void handleContextRefresh(ContextRefreshedEvent event) {
6549

6650
@EventListener
6751
public void handleApplicationReady(ApplicationReadyEvent event) {
68-
log.info("=============== " + APP_NAME + " has successfully started. ===============");
52+
log.info("=============== Massive Attack API has successfully started. ===============");
6953

7054
}
7155

src/main/java/fr/insee/sabianedata/ws/repository/InMemoryTrainingScenarioRepository.java

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,19 @@
1616
import fr.insee.sabianedata.ws.service.ExtractionService;
1717
import lombok.RequiredArgsConstructor;
1818
import lombok.extern.slf4j.Slf4j;
19-
import org.apache.commons.io.FileUtils;
19+
import org.springframework.core.io.Resource;
20+
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
21+
import org.springframework.core.io.support.ResourcePatternResolver;
22+
import org.springframework.util.StreamUtils;
23+
import java.io.OutputStream;
2024
import org.springframework.core.io.ResourceLoader;
2125
import org.springframework.stereotype.Component;
2226
import org.springframework.util.FileSystemUtils;
2327

2428
import jakarta.annotation.PostConstruct;
2529
import jakarta.annotation.PreDestroy;
26-
import java.io.File;
27-
import java.io.FileInputStream;
28-
import java.io.IOException;
29-
import java.io.InputStream;
30+
31+
import java.io.*;
3032
import java.nio.file.Files;
3133
import java.nio.file.Path;
3234
import java.util.*;
@@ -105,22 +107,43 @@ private void setupTempFolders() throws IOException {
105107
Path scenariiPath = tempScenariiFolder.toPath().toRealPath(); // resolves symlinks in scenarii subfolder
106108

107109
// Ensure the scenarii folder is truly a subdirectory of the base temp folder
108-
// This prevents path tricks or symlink-based attacks that could redirect outside of temp
109110
if (!scenariiPath.startsWith(realBasePath)) {
110111
throw new IOException("Potential directory traversal or symlink attack.");
111112
}
112113

113-
// Load scenarii files from the classpath
114-
File scenariosFolder = resourceLoader.getResource("classpath:scenarii").getFile();
115-
if (!scenariosFolder.exists()) {
116-
log.error("Scenarii folder not found in classpath.");
117-
throw new IOException("Scenarii folder not found in classpath.");
114+
// Load scenarii files
115+
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
116+
Resource[] resources = resolver.getResources("classpath*:/scenarii/**");
117+
118+
if (resources.length == 0) {
119+
log.error("Scenarii folder not found in classpath or is empty.");
120+
throw new IOException("Scenarii resources not found in classpath.");
118121
}
119122

120-
// Safely copy classpath scenarii files into the validated temp/scenarii folder
121-
FileUtils.copyDirectory(scenariosFolder, tempScenariiFolder);
123+
for(Resource resource : resources) {
124+
// handle only files
125+
if (!resource.isReadable()) {
126+
continue;
127+
}
128+
129+
String urlPath = resource.getURL().toString();
130+
int idx = urlPath.indexOf("/scenarii/");
131+
String relativePath = urlPath.substring(idx + "/scenarii/".length());
132+
133+
File targetFile = new File(tempScenariiFolder, relativePath);
134+
File parent = targetFile.getParentFile();
135+
if (!parent.exists() && !parent.mkdirs()) {
136+
throw new IOException("Failed to create directory: " + parent);
137+
}
138+
139+
try (InputStream in = resource.getInputStream();
140+
OutputStream out = Files.newOutputStream(targetFile.toPath())) {
141+
StreamUtils.copy(in, out);
142+
}
143+
}
122144
}
123145

146+
124147
private void loadScenarios() {
125148
File[] scenarioFolders = tempScenariiFolder.listFiles();
126149
checkScenarioFolder(scenarioFolders);

src/main/resources/application.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
spring:
2+
config:
3+
name: sabdatab
4+
security:
5+
oauth2:
6+
resourceserver:
7+
jwt:
8+
issuer-uri: ${feature.oidc.authServerUrl}/realms/${feature.oidc.realm}
9+
10+
application:
11+
host: http://localhost:8080
12+
cors-origins: '*'
13+
temp-folder: logs/myTemp
14+
management-url: http://localhost:8888
15+
questionnaire-url: http://localhost:9999
16+
17+
feature:
18+
oidc:
19+
enabled: true
20+
authServerHost: http://localhost:7080
21+
application-host: ${application.host}
22+
authServerUrl: ${feature.oidc.authServerHost}
23+
realm: sabiane
24+
principalAttribute: preferred_username
25+
clientId: myclient
26+
swagger:
27+
enabled: true
28+
29+
springdoc:
30+
swagger-ui:
31+
path: /
32+
oauth:
33+
clientId: ${feature.oidc.clientId}
34+
oauth2RedirectUrl: ${application.host}/swagger-ui/oauth2-redirect.html
35+
try-it-out-enabled: true
36+
doc-expansion: none
37+
38+
logging:
39+
appender: CONSOLE # CONSOLE | ROLLING_FILE
40+
level:
41+
root: INFO
42+
fr:
43+
insee:
44+
sabianedata: INFO
45+
pattern:
46+
console: "%d{YYYY-MM-dd HH:mm:ss.SSS} [%X{id}][%X{user}][%X{method} %X{path}] [%thread] %-5level %logger{36} - %m%n"
47+
file: ${logging.pattern.console}
48+
logback:
49+
rollingpolicy:
50+
max-history: 90

src/main/resources/log4j2.xml

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)