Skip to content

Commit 6108633

Browse files
R2.3.0
1 parent f721a00 commit 6108633

39 files changed

Lines changed: 2011 additions & 108 deletions

README.md

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -363,22 +363,19 @@ For an IDE start:
363363

364364
#### Prerequisites:
365365

366-
Connecting to the RISE PoPP Server only works if you’ve been granted access. To get onto the allowlist, please visit the [gematik Anfrageportal](https://service.gematik.de/servicedesk/customer/portal/37).
367-
You will get the correct endpoint with your request.
368-
369-
#### 1. Choose the profile
370-
371-
External customers use no Spring profile. Configure the RISE endpoint you received via the [gematik Anfrageportal](https://service.gematik.de/servicedesk/customer/portal/37) in `application.yaml`.
372-
373-
#### 2. Start the PoPP-Client locally
366+
Configure the `application.yaml` to match your setup. The correct endpoint
367+
```
368+
wss://popp.dev.poppservice.de:443/popp/practitioner/api/v1/token-generation-ehc
369+
```
370+
is already included.
374371
375-
External customers:
372+
#### 1a. Start the PoPP-Client locally
376373
377374
```bash
378375
./mvnw -pl popp-client spring-boot:run
379376
```
380377

381-
#### 3. Start the PoPP-Client via Docker
378+
#### 1b. Start the PoPP-Client via Docker
382379

383380
```bash
384381
docker run --rm -p 8081:8081 -p 9001:9001 \

ReleaseNotes.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@
66
- If your eGK has an older CVCA you may get problems while testing with the RÍSE PoPP-Service
77
- Standard-Kartenleser with Docker is not supported
88

9+
## Release 2.3.0
10+
11+
### added
12+
- Added Well-Known endpoints for OpenID Federation and signed JWKS:
13+
- /.well-known/openid-federation (entity statement JWT)
14+
- /.well-known/signed-jwks (signed JWK set)
15+
- URL for RISE PoPP Service is now public in README and application.yaml
16+
17+
### fixed
18+
- PoPP server health check
19+
920
## Release 2.2.0
1021

1122
### added

pom.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
<parent>
44
<groupId>org.springframework.boot</groupId>
55
<artifactId>spring-boot-starter-parent</artifactId>
6-
<version>4.0.5</version>
6+
<version>4.0.6</version>
77
</parent>
88
<groupId>de.gematik.refpopp</groupId>
99
<artifactId>popp-example-impl-global</artifactId>
10-
<version>2.2.0</version>
10+
<version>2.3.0</version>
1111
<packaging>pom</packaging>
1212
<name>popp-sample-code</name>
1313
<description>PoPP - example implementation</description>
@@ -42,7 +42,7 @@
4242
<!-- docker.registry.gematik will be set in Jenkinsfile -->
4343
<docker.registry.gematik>local</docker.registry.gematik>
4444
<java.version>21</java.version>
45-
<spring-boot.version>4.0.5</spring-boot.version>
45+
<spring-boot.version>4.0.6</spring-boot.version>
4646
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
4747
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
4848
<sonar.coverage.jacoco.xmlReportPaths>
@@ -60,7 +60,7 @@
6060
<version.docker-maven-plugin>0.48.1</version.docker-maven-plugin>
6161
<version.jacoco-maven-plugin>0.8.14</version.jacoco-maven-plugin>
6262
<version.jjwt>0.13.0</version.jjwt>
63-
<version.lombok>1.18.44</version.lombok>
63+
<version.lombok>1.18.46</version.lombok>
6464
<version.maven>3.8.6</version.maven>
6565
<version.maven-clean-plugin>3.5.0</version.maven-clean-plugin>
6666
<version.maven-compiler-plugin>3.15.0</version.maven-compiler-plugin>
@@ -77,7 +77,7 @@
7777
<version.maven-surefire-plugin>3.5.5</version.maven-surefire-plugin>
7878
<version.central-publishing-maven-plugin>0.10.0</version.central-publishing-maven-plugin>
7979
<version.openhealth.healthcard>0.3.0-alpha1</version.openhealth.healthcard>
80-
<version.sonar-maven-plugin>5.5.0.6356</version.sonar-maven-plugin>
80+
<version.sonar-maven-plugin>5.6.0.6792</version.sonar-maven-plugin>
8181
<version.spotless-maven-plugin>3.4.0</version.spotless-maven-plugin>
8282
<version.spotless.google-java-format>1.27.0</version.spotless.google-java-format>
8383
<version.spring-boot-maven-plugin>3.3.2</version.spring-boot-maven-plugin>
@@ -146,7 +146,7 @@
146146
<dependency>
147147
<groupId>commons-io</groupId>
148148
<artifactId>commons-io</artifactId>
149-
<version>2.21.0</version>
149+
<version>2.22.0</version>
150150
</dependency>
151151
<dependency>
152152
<groupId>org.jacoco</groupId>

popp-client/docker/Dockerfile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ ARG VERSION
77
LABEL de.gematik.vendor="gematik GmbH" \
88
maintainer="software-development@gematik.de" \
99
de.gematik.app="Gematik POPP-Client Example" \
10-
de.gematik.git-repo-name="...popp-example-impl-global.git" \
10+
de.gematik.git-repo-name="https://github.com/gematik/popp-sample-code.git" \
1111
de.gematik.commit-sha=$COMMIT_HASH \
1212
de.gematik.version=$VERSION
1313

@@ -30,7 +30,8 @@ ARG GROUPID=10000
3030
# Run as User (not root)
3131
USER $USERID:$GROUPID
3232

33-
COPY --chown=$USERID:$GROUPID popp-client*.jar /app/popp-client.jar
33+
ARG JAR_PATH=popp-client*.jar
34+
COPY --chown=$USERID:$GROUPID ${JAR_PATH} /app/popp-client.jar
3435

3536
# Expose the port that the application runs on
3637
EXPOSE 8081

popp-client/pom.xml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
<parent>
88
<groupId>de.gematik.refpopp</groupId>
99
<artifactId>popp-example-impl-global</artifactId>
10-
<version>2.2.0</version>
10+
<version>2.3.0</version>
1111
<relativePath>../pom.xml</relativePath>
1212
</parent>
1313

1414
<artifactId>popp-client</artifactId>
15-
<version>2.2.0</version>
15+
<version>2.3.0</version>
1616
<packaging>jar</packaging>
1717

1818
<name>popp-client</name>
@@ -124,17 +124,17 @@
124124
<dependency>
125125
<groupId>org.bouncycastle</groupId>
126126
<artifactId>bcprov-jdk18on</artifactId>
127-
<version>1.83</version>
127+
<version>1.84</version>
128128
</dependency>
129129
<dependency>
130130
<groupId>org.bouncycastle</groupId>
131131
<artifactId>bcpkix-jdk18on</artifactId>
132-
<version>1.83</version>
132+
<version>1.84</version>
133133
</dependency>
134134
<dependency>
135135
<groupId>org.bouncycastle</groupId>
136136
<artifactId>bctls-jdk18on</artifactId>
137-
<version>1.83</version>
137+
<version>1.84</version>
138138
</dependency>
139139
<dependency>
140140
<groupId>org.springframework.boot</groupId>
@@ -143,7 +143,7 @@
143143
<dependency>
144144
<groupId>org.apache.httpcomponents.client5</groupId>
145145
<artifactId>httpclient5</artifactId>
146-
<version>5.6</version>
146+
<version>5.6.1</version>
147147
</dependency>
148148
<dependency>
149149
<groupId>com.google.zxing</groupId>
@@ -223,7 +223,7 @@
223223
<plugin>
224224
<groupId>org.apache.maven.plugins</groupId>
225225
<artifactId>maven-dependency-plugin</artifactId>
226-
<version>3.9.0</version>
226+
<version>3.10.0</version>
227227
<executions>
228228
<execution>
229229
<id>unpack-openhealth-linux-natives</id>

popp-client/src/main/java/de/gematik/refpopp/popp_client/client/ClientServerCommunicationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void connect() {
5454
try {
5555
secureWebSocketClient.connectBlocking();
5656
} catch (final Exception e) {
57-
log.error("Error connecting to WebSocket server: {}", e.getMessage());
57+
log.error("Error connecting to WebSocket server: {}", e.getMessage(), e);
5858
Thread.currentThread().interrupt();
5959
}
6060
}

popp-client/src/main/java/de/gematik/refpopp/popp_client/client/SecureWebSocketClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ public void connectBlocking() {
237237
}
238238
} catch (InterruptedException e) {
239239
Thread.currentThread().interrupt();
240-
throw new RuntimeException(e);
240+
throw new IllegalStateException(
241+
"Thread was interrupted while waiting for WebSocket connection", e);
241242
}
242243
}
243244

popp-client/src/main/java/de/gematik/refpopp/popp_client/controller/TokenController.java

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,27 +131,27 @@ public class TokenController {
131131
public ResponseEntity<PoppClientResponse> createToken(
132132
@Valid @RequestBody PoppClientRequest request) {
133133
String clientSessionId = request.clientSessionId();
134+
log.info(
135+
"| Started 'generate PoPP Token' with clientSessionId '{}' and communicationType" + " '{}'",
136+
clientSessionId,
137+
request.communicationType().getType());
134138
try {
135139
if (request.communicationType().requiresCardReader()) {
136140
cardReaderService.startCheckForCardReader();
137141
}
138142
String token = startCommunication(request.communicationType(), clientSessionId);
139-
143+
log.info("| Finished 'generate PoPP Token' successfully");
140144
return ResponseEntity.ok(PoppClientResponse.ok(token));
141145
} catch (UnsupportedOperationException e) {
142-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
143-
.body(PoppClientResponse.error(e.getMessage()));
146+
return buildErrorResponse(HttpStatus.BAD_REQUEST, e.getMessage(), e);
144147
} catch (RuntimeException e) {
145148
if (e.getCause() instanceof java.util.concurrent.TimeoutException) {
146-
return ResponseEntity.status(HttpStatus.GATEWAY_TIMEOUT)
147-
.body(PoppClientResponse.error("Token generation timed out"));
149+
return buildErrorResponse(HttpStatus.GATEWAY_TIMEOUT, "Token generation timed out", e);
148150
}
149-
150-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
151-
.body(PoppClientResponse.error("Unexpected error: " + e.getMessage()));
151+
return buildErrorResponse(
152+
HttpStatus.INTERNAL_SERVER_ERROR, "Unexpected error: " + e.getMessage(), e);
152153
} catch (Exception e) {
153-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
154-
.body(PoppClientResponse.error(e.getMessage()));
154+
return buildErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e);
155155
}
156156
}
157157

@@ -169,4 +169,16 @@ private String startCommunication(CardConnectionType type, String clientSessionI
169169
default -> throw new UnsupportedOperationException("Unsupported type: " + type);
170170
};
171171
}
172+
173+
private ResponseEntity<PoppClientResponse> buildErrorResponse(
174+
HttpStatus status, String errorMessage, Exception exception) {
175+
log.error(
176+
"| Finished 'generate PoPP Token' with HTTP status '{}', error message '{}' and stack trace"
177+
+ " '{}'",
178+
status.getReasonPhrase(),
179+
exception.getMessage(),
180+
exception.getStackTrace());
181+
182+
return ResponseEntity.status(status).body(PoppClientResponse.error(errorMessage));
183+
}
172184
}

popp-client/src/main/resources/application.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ springdoc:
77
api-docs:
88
enabled: true
99

10-
# obtain the Rise URL via the "Gematik-Anfrageportal" and configure it here
1110
popp-server:
12-
url: wss://popp-zeta-ingress:443/ws
11+
url: wss://popp.dev.poppservice.de:443/popp/practitioner/api/v1/token-generation-ehc
1312
connector:
1413
end-point-url: ${CONNECTOR_END_POINT_URL:http://ti-konnektor/cardservice}
1514

popp-client/src/test/java/de/gematik/refpopp/popp_client/client/SecureWebSocketClientTest.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
package de.gematik.refpopp.popp_client.client;
2222

2323
import static org.assertj.core.api.Assertions.assertThat;
24+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2425
import static org.junit.jupiter.api.Assertions.assertThrows;
2526
import static org.mockito.ArgumentMatchers.anyString;
2627
import static org.mockito.Mockito.*;
@@ -210,7 +211,7 @@ void testConnectBlocking() {
210211
}
211212

212213
@Test
213-
void testConnectBlocking_timeout() throws Exception {
214+
void testConnectBlockingTimeout() throws Exception {
214215
// given
215216
var latchSpy = spy(new CountDownLatch(1));
216217
setPrivateField(sut, "sessionReady", latchSpy);
@@ -234,7 +235,7 @@ void testConnectBlocking_timeout() throws Exception {
234235
}
235236

236237
@Test
237-
void testConnectBlocking_interrupted() throws Exception {
238+
void testConnectBlockingInterrupted() throws Exception {
238239
// given
239240
var latchSpy = spy(new CountDownLatch(1));
240241
setPrivateField(sut, "sessionReady", latchSpy);
@@ -258,7 +259,7 @@ void testConnectBlocking_interrupted() throws Exception {
258259
}
259260

260261
@Test
261-
void testConnectBlocking_handlesTextMessage() throws Exception {
262+
void testConnectBlockingHandlesTextMessage() throws Exception {
262263
// given
263264
var sessionMock = mock(WsClientExtension.WsSession.class);
264265
var textMsg = mock(WsClientExtension.WsMessage.Text.class);
@@ -296,7 +297,7 @@ void testConnectBlocking_handlesTextMessage() throws Exception {
296297
}
297298

298299
@Test
299-
void testConnectBlocking_handlesBinaryMessage() throws Exception {
300+
void testConnectBlockingHandlesBinaryMessage() throws Exception {
300301
// given
301302
var sessionMock = mock(WsClientExtension.WsSession.class);
302303
var bytes = new byte[] {1, 2, 3, 4};
@@ -328,6 +329,31 @@ void testConnectBlocking_handlesBinaryMessage() throws Exception {
328329
assertThat(sutSpy.isOpen()).isTrue();
329330
}
330331

332+
@Test
333+
void connectBlockingThrowsIllegalStateExceptionAndInterruptsThreadWhenAwaitIsInterrupted()
334+
throws Exception {
335+
// given
336+
var latchSpy = spy(new CountDownLatch(1));
337+
setPrivateField(sut, "sessionReady", latchSpy);
338+
339+
doThrow(new InterruptedException("interrupted"))
340+
.when(latchSpy)
341+
.await(anyLong(), any(TimeUnit.class));
342+
343+
// clear interrupted flag before test
344+
Thread.interrupted();
345+
346+
// when / then
347+
assertThatThrownBy(() -> sut.connectBlocking())
348+
.isInstanceOf(IllegalStateException.class)
349+
.hasMessage("Thread was interrupted while waiting for WebSocket connection")
350+
.hasCauseInstanceOf(InterruptedException.class);
351+
352+
assertThat(Thread.currentThread().isInterrupted()).isTrue();
353+
354+
Thread.interrupted();
355+
}
356+
331357
private void setPrivateField(Object target, String fieldName, Object value) throws Exception {
332358
Field field = target.getClass().getDeclaredField(fieldName);
333359
field.setAccessible(true);

0 commit comments

Comments
 (0)