Skip to content

Commit e237e11

Browse files
R2.4.1
1 parent c3476a6 commit e237e11

43 files changed

Lines changed: 2875 additions & 69 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ReleaseNotes.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,24 @@
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.4.1
10+
11+
### added
12+
- Added support for selecting a specific card terminal via ct-id when multiple terminals are connected to a Konnektor
13+
- Added endpoint (popp-client) for popp token verification: /token/verify
14+
15+
### changed
16+
- Replaced static actorId value with value extracted from the zeta-user-info header
17+
- Updated ZETA version to 1.0.1
18+
919
## Release 2.4.0
1020

1121
### changed
1222
- Replaced the former Smartcard-library based CVC and trusted-channel handling in PoPP client and server with OpenHealth-based `CvCertificate`, healthcard parsing, and crypto verification APIs
1323
- Reworked trusted CVC directory loading and trusted-channel chain building on the server to use OpenHealth instead of `TrustCenter` and `SecureMessagingConverterSoftware`
1424
- Switched the configured trusted-channel service identity validation to OpenHealth using the configured PKCS#8 key material directly
1525
- Simplified server-side key handling by removing obsolete parser and factory layers around private keys and JCA key store access
16-
- Add support for Contactless Virtual Card
26+
- Added support for Contactless Virtual Card
1727

1828
### fixed
1929
- Fixed contact-based and contactless CVC signature verification and nonce verification to use the same OpenHealth-based verification logic across scenarios

docker/compose.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ services:
66
environment:
77
- SPRING_PROFILES_ACTIVE=dev-local
88
- ZETA_AUTHENTICATION_SMB_KEYFILE=/app/smcb_private.p12
9+
- FEDERATION_ENTITY_STATEMENT_URL=http://popp-server:8443/.well-known/openid-federation
910
networks:
1011
- popp-network
1112
ports:
@@ -26,6 +27,7 @@ services:
2627
- IDENTITIES_LOCATION=classpath:identities
2728
- CERT_HASH_IMPORT_LOCATION=file:/app/import
2829
- SPRING_DATASOURCE_URL=jdbc:postgresql://popp-server-db:5432/egk_hash_db
30+
- FEDERATION_JWKS_URL=http://popp-server:8443
2931
networks:
3032
- popp-network
3133
depends_on:
@@ -60,7 +62,7 @@ services:
6062
- popp-zeta-pep
6163

6264
popp-zeta-pep:
63-
image: europe-west3-docker.pkg.dev/gematik-pt-zeta-prod/zeta-dcr/ngx_pep:0.5.1
65+
image: europe-west3-docker.pkg.dev/gematik-pt-zeta-prod/zeta-dcr/ngx_pep:1.0.1
6466
environment:
6567
- POPP_SERVER_HOST=popp-server:8443
6668
- HTTP_PROXY=
@@ -85,7 +87,7 @@ services:
8587
popp-server:
8688
condition: service_started # TODO: change to "service_healthy" when healthcheck is available
8789
popp-zeta-pdp:
88-
image: europe-west3-docker.pkg.dev/gematik-pt-zeta-prod/zeta-dcr/keycloak-zeta:0.5.1
90+
image: europe-west3-docker.pkg.dev/gematik-pt-zeta-prod/zeta-dcr/keycloak-zeta:1.0.1
8991
environment:
9092
KC_BOOTSTRAP_ADMIN_USERNAME: admin
9193
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
@@ -162,7 +164,7 @@ services:
162164

163165
popp-zeta-pdp-opa:
164166
container_name: popp-zeta-pdp-opa
165-
image: openpolicyagent/opa:1.15.2-static
167+
image: openpolicyagent/opa:1.16.2
166168
environment:
167169
HTTP_PROXY: ""
168170
HTTPS_PROXY: ""

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</parent>
88
<groupId>de.gematik.refpopp</groupId>
99
<artifactId>popp-example-impl-global</artifactId>
10-
<version>2.4.0</version>
10+
<version>2.4.1</version>
1111
<packaging>pom</packaging>
1212
<name>popp-sample-code</name>
1313
<description>PoPP - example implementation</description>
@@ -64,7 +64,7 @@
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>
67-
<version.maven-enforcer-plugin>3.6.2</version.maven-enforcer-plugin>
67+
<version.maven-enforcer-plugin>3.6.3</version.maven-enforcer-plugin>
6868
<version.maven-failsafe-plugin>3.5.5</version.maven-failsafe-plugin>
6969
<version.maven-gpg-plugin>3.2.8</version.maven-gpg-plugin>
7070
<version.maven-javadoc-plugin>3.12.0</version.maven-javadoc-plugin>
@@ -78,10 +78,10 @@
7878
<version.central-publishing-maven-plugin>0.10.0</version.central-publishing-maven-plugin>
7979
<version.openhealth.healthcard>0.4.0-alpha1</version.openhealth.healthcard>
8080
<version.sonar-maven-plugin>5.6.0.6792</version.sonar-maven-plugin>
81-
<version.spotless-maven-plugin>3.4.0</version.spotless-maven-plugin>
81+
<version.spotless-maven-plugin>3.5.1</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>
84-
<version.zeta-sdk-jvm>0.5.1</version.zeta-sdk-jvm>
84+
<version.zeta-sdk-jvm>1.0.1</version.zeta-sdk-jvm>
8585
<jackson-2-bom.version>2.21.1</jackson-2-bom.version>
8686
<jackson-bom.version>3.1.1</jackson-bom.version>
8787
<mockito.agent.jar>${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar</mockito.agent.jar>

popp-client/pom.xml

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

@@ -149,6 +149,11 @@
149149
<artifactId>javase</artifactId>
150150
<version>3.5.4</version>
151151
</dependency>
152+
<dependency>
153+
<groupId>com.nimbusds</groupId>
154+
<artifactId>nimbus-jose-jwt</artifactId>
155+
<version>10.9</version>
156+
</dependency>
152157
</dependencies>
153158

154159
<build>

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import de.gematik.refpopp.popp_client.client.events.WebSocketConnectionOpenedEvent;
2727
import de.gematik.refpopp.popp_client.configuration.PathResolver;
2828
import de.gematik.zeta.sdk.BuildConfig;
29-
import de.gematik.zeta.sdk.StorageConfig;
3029
import de.gematik.zeta.sdk.TpmConfig;
3130
import de.gematik.zeta.sdk.WsClientExtension;
3231
import de.gematik.zeta.sdk.ZetaSdk;
@@ -38,6 +37,7 @@
3837
import de.gematik.zeta.sdk.authentication.smb.SmbTokenProvider;
3938
import de.gematik.zeta.sdk.network.http.client.ZetaHttpClientBuilder;
4039
import de.gematik.zeta.sdk.storage.InMemoryStorage;
40+
import de.gematik.zeta.sdk.storage.StorageConfig;
4141
import io.ktor.client.plugins.logging.LogLevel;
4242
import jakarta.annotation.PostConstruct;
4343
import java.net.URI;
@@ -107,15 +107,20 @@ public SecureWebSocketClient(
107107
"demo-client",
108108
"0.2.0",
109109
"sdk-client",
110-
new StorageConfig(
111-
new InMemoryStorage(), "7aae7xXr8rnzVqjpYbosS0CFMrlprkD7jbVotm0fd+w="),
110+
new StorageConfig.Custom(new InMemoryStorage()),
112111
new TpmConfig() {},
113112
new AuthConfig(
114-
List.of("popp"), 30L, true, getTokenProvider(), AttestationConfig.software()),
113+
List.of("popp"),
114+
30L,
115+
true,
116+
getTokenProvider(),
117+
AttestationConfig.software(),
118+
""),
115119
createPlatformProductId(),
116120
new ZetaHttpClientBuilder("")
117121
.disableServerValidation(disableServerValidation)
118-
.logging(LogLevel.ALL, message -> log.info("Ktor HttpClient: {}", message)),
122+
.logging(LogLevel.ALL),
123+
null,
119124
null,
120125
null));
121126
}
@@ -207,7 +212,7 @@ public void connectBlocking() {
207212
zetaSdk,
208213
this.serverUri.toString(),
209214
builder -> {
210-
builder.disableServerValidation(true);
215+
builder.disableServerValidation(disableServerValidation);
211216
return Unit.INSTANCE;
212217
},
213218
new HashMap<>(),
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (Date see Readme), gematik GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* *******
17+
*
18+
* For additional notes and disclaimer from gematik and in case of changes by gematik find details in the "Readme" file.
19+
*/
20+
21+
package de.gematik.refpopp.popp_client.configuration;
22+
23+
import java.security.KeyStore;
24+
import org.springframework.beans.factory.annotation.Value;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.core.io.Resource;
28+
29+
@Configuration
30+
public class PoppTokenVerificationConfiguration {
31+
private final Resource location;
32+
private final String password;
33+
34+
public PoppTokenVerificationConfiguration(
35+
@Value("${federation.keystore.location}") Resource location,
36+
@Value("${federation.keystore.password}") String password) {
37+
this.location = location;
38+
this.password = password;
39+
}
40+
41+
@Bean
42+
public KeyStore keyStore() {
43+
try (var is = location.getInputStream()) {
44+
final var keyStore = KeyStore.getInstance("jks");
45+
keyStore.load(is, password.toCharArray());
46+
return keyStore;
47+
} catch (Exception e) {
48+
throw new IllegalStateException("Could not load key store", e);
49+
}
50+
}
51+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (Date see Readme), gematik GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* *******
17+
*
18+
* For additional notes and disclaimer from gematik and in case of changes by gematik find details in the "Readme" file.
19+
*/
20+
21+
package de.gematik.refpopp.popp_client.configuration;
22+
23+
import org.springframework.context.annotation.Bean;
24+
import org.springframework.context.annotation.Configuration;
25+
import org.springframework.web.client.RestClient;
26+
27+
@Configuration
28+
public class RestClientConfig {
29+
30+
@Bean
31+
public RestClient.Builder restClientBuilder() {
32+
return RestClient.builder();
33+
}
34+
}

popp-client/src/main/java/de/gematik/refpopp/popp_client/connector/eventservice/GetCardsClient.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,11 @@
3131
import de.gematik.ws.conn.connectorcontext.v2.ContextType;
3232
import de.gematik.ws.conn.eventservice.v7.GetCards;
3333
import de.gematik.ws.conn.eventservice.v7.GetCardsResponse;
34-
import java.util.List;
35-
import java.util.function.Supplier;
3634
import lombok.extern.slf4j.Slf4j;
3735
import org.apache.hc.client5.http.classic.HttpClient;
3836
import org.springframework.beans.factory.annotation.Autowired;
3937
import org.springframework.beans.factory.annotation.Qualifier;
38+
import org.springframework.beans.factory.annotation.Value;
4039
import org.springframework.context.annotation.Lazy;
4140
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
4241
import org.springframework.stereotype.Component;
@@ -49,18 +48,21 @@ public class GetCardsClient extends SoapClient {
4948

5049
private final Context context;
5150
private final ServiceEndpointProvider serviceEndpointProvider;
51+
private final String ctId;
5252

5353
public GetCardsClient(
5454
final Jaxb2Marshaller eventServiceMarshaller,
5555
final Context context,
5656
final ServiceEndpointProvider serviceEndpointProvider,
57-
@Autowired(required = false) @Qualifier("httpClientWithBC") HttpClient httpClient) {
57+
@Autowired(required = false) @Qualifier("httpClientWithBC") HttpClient httpClient,
58+
@Value("${connector.terminal-configuration.ct-id:}") String ctId) {
5859
super(
5960
eventServiceMarshaller,
60-
(Supplier<String>) () -> buildSoapAction(serviceEndpointProvider, SoapActions.GET_CARDS),
61+
() -> buildSoapAction(serviceEndpointProvider, SoapActions.GET_CARDS),
6162
httpClient);
6263
this.context = context;
6364
this.serviceEndpointProvider = serviceEndpointProvider;
65+
this.ctId = ctId;
6466
}
6567

6668
public DetermineCardHandleResponse performGetCards() {
@@ -69,14 +71,10 @@ public DetermineCardHandleResponse performGetCards() {
6971
log.info("Sending GetCards request to connector at {}", endpoint);
7072
final GetCardsResponse soapResponse =
7173
sendRequest(soapRequest, endpoint, GetCardsResponse.class);
72-
final DetermineCardHandleResponse determineCardHandleResponse =
73-
new DetermineCardHandleResponse();
74+
final var determineCardHandleResponse = new DetermineCardHandleResponse();
7475

75-
final List<String> cardHandles =
76-
soapResponse.getCards().getCard().stream()
77-
.filter(card -> CardTypeType.EGK.equals(card.getCardType()))
78-
.map(CardInfoType::getCardHandle)
79-
.toList();
76+
final var cardHandles =
77+
soapResponse.getCards().getCard().stream().map(CardInfoType::getCardHandle).toList();
8078

8179
determineCardHandleResponse.setCardHandles(cardHandles);
8280
return determineCardHandleResponse;
@@ -90,6 +88,10 @@ private GetCards createGetCards() {
9088
final ContextType contextType = getContextType();
9189
final GetCards getCards = new GetCards();
9290
getCards.setContext(contextType);
91+
if (!ctId.isBlank()) {
92+
getCards.setCtId(ctId);
93+
}
94+
getCards.setCardType(CardTypeType.EGK);
9395

9496
return getCards;
9597
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (Date see Readme), gematik GmbH
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* *******
17+
*
18+
* For additional notes and disclaimer from gematik and in case of changes by gematik find details in the "Readme" file.
19+
*/
20+
21+
package de.gematik.refpopp.popp_client.controller;
22+
23+
import lombok.Getter;
24+
import org.springframework.http.HttpStatus;
25+
26+
@Getter
27+
public enum ErrorCode {
28+
TOKEN_MISSING(HttpStatus.BAD_REQUEST),
29+
TOKEN_MALFORMED(HttpStatus.BAD_REQUEST),
30+
31+
SIGNATURE_INVALID(HttpStatus.UNAUTHORIZED),
32+
ALGORITHM_INVALID(HttpStatus.UNAUTHORIZED),
33+
KID_NOT_FOUND(HttpStatus.UNAUTHORIZED),
34+
35+
ISSUER_INVALID(HttpStatus.UNAUTHORIZED),
36+
ACTOR_MISMATCH(HttpStatus.FORBIDDEN),
37+
TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED),
38+
39+
JWKS_FETCH_FAILED(HttpStatus.SERVICE_UNAVAILABLE),
40+
ENTITY_STATEMENT_INVALID(HttpStatus.UNAUTHORIZED),
41+
42+
OCSP_CHECK_FAILED(HttpStatus.SERVICE_UNAVAILABLE),
43+
CERTIFICATE_INVALID(HttpStatus.UNAUTHORIZED),
44+
45+
INTERNAL_ERROR(HttpStatus.INTERNAL_SERVER_ERROR),
46+
47+
ENTITY_STATEMENT_FETCH_FAILED(HttpStatus.SERVICE_UNAVAILABLE),
48+
PUBLIC_KEY_UNSUPPORTED(HttpStatus.UNAUTHORIZED),
49+
ACTOR_ID_INVALID(HttpStatus.UNAUTHORIZED);
50+
51+
private final HttpStatus httpStatus;
52+
53+
ErrorCode(HttpStatus httpStatus) {
54+
this.httpStatus = httpStatus;
55+
}
56+
}

0 commit comments

Comments
 (0)