Skip to content

Commit 3d43a82

Browse files
feat: add Credential Issuance test cases (CS) (#22)
* add issuance tests for CS * fix default test harness * fix correlation ID
1 parent 950b370 commit 3d43a82

File tree

24 files changed

+765
-116
lines changed

24 files changed

+765
-116
lines changed

config/tck/sample.tck.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
# Contains sample configuration options
2+
dataspacetck.test.package=org.eclipse.dataspacetck.dcp.verification.presentation
3+
#dataspacetck.test.package=org.eclipse.dataspacetck.dcp.verification.issuance.cs
4+
dataspacetck.credentials.correlation.id=foobar
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Metaform Systems Inc.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Metaform Systems Inc. - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataspacetck.dcp.system.annotation;
16+
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.Target;
20+
21+
import static java.lang.annotation.ElementType.FIELD;
22+
import static java.lang.annotation.ElementType.PARAMETER;
23+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
24+
25+
/**
26+
* Annotation used to inject randomly generated credentials of the given type into a test method
27+
*/
28+
@Inherited
29+
@Retention(RUNTIME)
30+
@Target({FIELD, PARAMETER})
31+
public @interface Credential {
32+
String value();
33+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2025 Metaform Systems Inc.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Metaform Systems Inc. - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataspacetck.dcp.system.annotation;
16+
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.Target;
20+
21+
import static java.lang.annotation.ElementType.FIELD;
22+
import static java.lang.annotation.ElementType.PARAMETER;
23+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
24+
25+
/**
26+
* Holder-assigned Process Identifier (PID) when dealing with Credential Issuance messages
27+
*/
28+
@Inherited
29+
@Retention(RUNTIME)
30+
@Target({FIELD, PARAMETER})
31+
public @interface HolderPid {
32+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2025 Metaform Systems Inc.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Metaform Systems Inc. - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.dataspacetck.dcp.system.annotation;
16+
17+
import org.eclipse.dataspacetck.core.api.system.Inject;
18+
19+
import java.lang.annotation.Inherited;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.Target;
22+
23+
import static java.lang.annotation.ElementType.FIELD;
24+
import static java.lang.annotation.ElementType.PARAMETER;
25+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
26+
27+
/**
28+
* For field injection, used in conjunction with {@link Inject} to specify the injection of a verifier service.
29+
*/
30+
@Inherited
31+
@Retention(RUNTIME)
32+
@Target({FIELD, PARAMETER})
33+
public @interface Issuer {
34+
}

dcp-api/src/main/java/org/eclipse/dataspacetck/dcp/system/annotation/RoleType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
* A holder, verifier or third-party.
1919
*/
2020
public enum RoleType {
21-
HOLDER, VERIFIER, THIRD_PARTY
21+
HOLDER, ISSUER, VERIFIER, THIRD_PARTY
2222
}

dcp-api/src/main/java/org/eclipse/dataspacetck/dcp/system/cs/CredentialService.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414

1515
package org.eclipse.dataspacetck.dcp.system.cs;
1616

17-
import org.eclipse.dataspacetck.dcp.system.model.vc.VcContainer;
1817
import org.eclipse.dataspacetck.dcp.system.service.Result;
1918

20-
import java.util.List;
19+
import java.io.InputStream;
2120
import java.util.Map;
2221

2322
/**
@@ -33,5 +32,5 @@ public interface CredentialService {
3332
/**
3433
* Writes issued credentials.
3534
*/
36-
Result<Void> writeCredentials(String bearerDid, String correlationId, List<VcContainer> containers);
35+
Result<Void> writeCredentials(String idTokenJwt, InputStream body);
3736
}

dcp-api/src/main/java/org/eclipse/dataspacetck/dcp/system/message/DcpConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public interface DcpConstants {
5757

5858
String PRESENTATION_QUERY_PATH = "/presentations/query";
5959

60+
String CREDENTIALS_PATH = "/credentials";
61+
6062
String CREDENTIAL_OFFER_MESSAGE_TYPE = "CredentialOfferMessage";
6163

6264
String CREDENTIAL_MESSAGE_TYPE = "CredentialMessage";

dcp-api/src/main/java/org/eclipse/dataspacetck/dcp/system/service/Result.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,16 @@
1818
* Result of a service invocation.
1919
*/
2020
public class Result<T> {
21-
public enum ErrorType {
22-
NOT_FOUND, UNAUTHORIZED, BAD_REQUEST, GENERAL_ERROR, NO_ERROR
23-
}
24-
2521
private final T content;
2622
private final String failure;
2723
private final ErrorType errorType;
2824

25+
private Result(T content, String failure, ErrorType errorType) {
26+
this.content = content;
27+
this.failure = failure;
28+
this.errorType = errorType;
29+
}
30+
2931
public static Result<Void> success() {
3032
return new Result<>(null, null, ErrorType.NO_ERROR);
3133
}
@@ -34,6 +36,14 @@ public static <T> Result<T> success(T content) {
3436
return new Result<>(content, null, ErrorType.NO_ERROR);
3537
}
3638

39+
public static <T> Result<T> failure(String failure) {
40+
return new Result<>(null, failure, ErrorType.GENERAL_ERROR);
41+
}
42+
43+
public static <T> Result<T> failure(String failure, ErrorType errorType) {
44+
return new Result<>(null, failure, errorType);
45+
}
46+
3747
public boolean succeeded() {
3848
return failure == null;
3949
}
@@ -54,22 +64,12 @@ public ErrorType getErrorType() {
5464
return errorType;
5565
}
5666

57-
public static <T> Result<T> failure(String failure) {
58-
return new Result<>(null, failure, ErrorType.GENERAL_ERROR);
59-
}
60-
61-
public static <T> Result<T> failure(String failure, ErrorType errorType) {
62-
return new Result<>(null, failure, errorType);
63-
}
64-
6567
public <R> R convert() {
6668
//noinspection unchecked
6769
return (R) this;
6870
}
6971

70-
private Result(T content, String failure, ErrorType errorType) {
71-
this.content = content;
72-
this.failure = failure;
73-
this.errorType = errorType;
72+
public enum ErrorType {
73+
NOT_FOUND, UNAUTHORIZED, BAD_REQUEST, GENERAL_ERROR, NO_ERROR
7474
}
7575
}

dcp-system/src/main/java/org/eclipse/dataspacetck/dcp/system/DcpSystemLauncher.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,21 @@
1919
import org.eclipse.dataspacetck.core.spi.system.SystemConfiguration;
2020
import org.eclipse.dataspacetck.core.spi.system.SystemLauncher;
2121
import org.eclipse.dataspacetck.dcp.system.annotation.AuthToken;
22+
import org.eclipse.dataspacetck.dcp.system.annotation.Credential;
2223
import org.eclipse.dataspacetck.dcp.system.annotation.Did;
2324
import org.eclipse.dataspacetck.dcp.system.annotation.Holder;
25+
import org.eclipse.dataspacetck.dcp.system.annotation.HolderPid;
2426
import org.eclipse.dataspacetck.dcp.system.annotation.IssueCredentials;
27+
import org.eclipse.dataspacetck.dcp.system.annotation.Issuer;
2528
import org.eclipse.dataspacetck.dcp.system.annotation.ThirdParty;
2629
import org.eclipse.dataspacetck.dcp.system.annotation.Verifier;
2730
import org.eclipse.dataspacetck.dcp.system.assembly.BaseAssembly;
2831
import org.eclipse.dataspacetck.dcp.system.assembly.ServiceAssembly;
2932
import org.eclipse.dataspacetck.dcp.system.crypto.KeyService;
3033
import org.eclipse.dataspacetck.dcp.system.cs.CredentialService;
3134
import org.eclipse.dataspacetck.dcp.system.did.DidService;
35+
import org.eclipse.dataspacetck.dcp.system.generation.JwtCredentialGenerator;
36+
import org.eclipse.dataspacetck.dcp.system.model.vc.VcContainer;
3237
import org.jetbrains.annotations.Nullable;
3338

3439
import java.lang.annotation.Annotation;
@@ -55,7 +60,8 @@ public <T> boolean providesService(Class<T> type) {
5560
return type.isAssignableFrom(CredentialService.class) ||
5661
type.isAssignableFrom(DidService.class) ||
5762
type.isAssignableFrom(String.class) ||
58-
type.isAssignableFrom(KeyService.class);
63+
type.isAssignableFrom(KeyService.class) ||
64+
type.isAssignableFrom(VcContainer.class);
5965
}
6066

6167
@Nullable
@@ -65,13 +71,23 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
6571
var assembly = serviceAssemblies.computeIfAbsent(scopeId, id -> new ServiceAssembly(baseAssembly, resolver, configuration));
6672
if (type.isAssignableFrom(CredentialService.class)) {
6773
return type.cast(assembly.getCredentialService());
74+
} else if (type.isAssignableFrom(VcContainer.class)) {
75+
if (hasAnnotation(Credential.class, configuration)) {
76+
var gen = new JwtCredentialGenerator(baseAssembly.getIssuerDid(), baseAssembly.getIssuerKeyService());
77+
var credentialType = getAnnotation(Credential.class, configuration);
78+
if (credentialType.isPresent()) {
79+
return type.cast(assembly.createVcContainer(baseAssembly.getIssuerDid(), baseAssembly.getHolderDid(), gen, credentialType.get().value()));
80+
}
81+
}
6882
} else if (type.isAssignableFrom(KeyService.class)) {
6983
if (hasAnnotation(Verifier.class, configuration)) {
7084
return type.cast(baseAssembly.getVerifierKeyService());
7185
} else if (hasAnnotation(Holder.class, configuration)) {
7286
return type.cast(baseAssembly.getHolderKeyService());
7387
} else if (hasAnnotation(ThirdParty.class, configuration)) {
7488
return type.cast(baseAssembly.getThirdPartyKeyService());
89+
} else if (hasAnnotation(Issuer.class, configuration)) {
90+
return type.cast(baseAssembly.getIssuerKeyService());
7591
}
7692
} else if (type.isAssignableFrom(DidService.class)) {
7793
if (hasAnnotation(Verifier.class, configuration)) {
@@ -80,11 +96,16 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
8096
return type.cast(baseAssembly.getHolderDidService());
8197
} else if (hasAnnotation(ThirdParty.class, configuration)) {
8298
return type.cast(baseAssembly.getThirdPartyDidService());
99+
} else if (hasAnnotation(Issuer.class, configuration)) {
100+
return type.cast(baseAssembly.getIssuerDidService());
83101
}
84102
} else if (type.isAssignableFrom(String.class)) {
85103
if (hasAnnotation(AuthToken.class, configuration)) {
86104
return createAuthToken(type, configuration, assembly);
87105
}
106+
if (hasAnnotation(HolderPid.class, configuration)) {
107+
return type.cast(baseAssembly.getHolderPid());
108+
}
88109

89110
var did = getAnnotation(Did.class, configuration);
90111
if (did.isPresent()) {
@@ -98,9 +119,10 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
98119
case THIRD_PARTY -> {
99120
return type.cast(baseAssembly.getThirdPartyDid());
100121
}
101-
default -> {
102-
throw new UnsupportedOperationException("Unsupported DID role: " + did.get().value());
122+
case ISSUER -> {
123+
return type.cast(baseAssembly.getIssuerDid());
103124
}
125+
default -> throw new UnsupportedOperationException("Unsupported DID role: " + did.get().value());
104126
}
105127
}
106128
}
@@ -110,7 +132,7 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
110132
@Override
111133
public void beforeExecution(ServiceConfiguration configuration, ServiceResolver resolver) {
112134
if (hasAnnotation(IssueCredentials.class, configuration)) {
113-
// TODO implement credential issuance
135+
serviceAssemblies.get(configuration.getScopeId()).issueCredentials(baseAssembly);
114136
}
115137
}
116138

dcp-system/src/main/java/org/eclipse/dataspacetck/dcp/system/assembly/BaseAssembly.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import java.util.Objects;
2929

3030
import static java.lang.String.format;
31+
import static java.util.Optional.ofNullable;
32+
import static java.util.UUID.randomUUID;
3133
import static org.eclipse.dataspacetck.core.api.system.SystemsConstants.TCK_CALLBACK_ADDRESS;
3234
import static org.eclipse.dataspacetck.core.api.system.SystemsConstants.TCK_DEFAULT_CALLBACK_ADDRESS;
3335
import static org.eclipse.dataspacetck.core.api.system.SystemsConstants.TCK_PREFIX;
@@ -52,6 +54,7 @@ public class BaseAssembly {
5254
private final KeyServiceImpl thirdPartyKeyService;
5355
private final DidServiceImpl thirdPartyDidService;
5456
private final ObjectMapper mapper;
57+
private final String holderPid;
5558

5659
public BaseAssembly(SystemConfiguration configuration) {
5760
mapper = new ObjectMapper();
@@ -68,6 +71,8 @@ public BaseAssembly(SystemConfiguration configuration) {
6871
holderDidService = new DidServiceImpl(holderDid, address, holderKeyService);
6972
holderTokenService = new TokenValidationServiceImpl(holderDid);
7073

74+
holderPid = ofNullable(configuration.getPropertyAsString(TCK_PREFIX + ".credentials.correlation.id", null)).orElseGet(() -> randomUUID().toString());
75+
7176
verifierTokenService = new TokenValidationServiceImpl(verifierDid);
7277
verifierKeyService = new KeyServiceImpl(Keys.generateEcKey());
7378
verifierDidService = new DidServiceImpl(verifierDid, address, verifierKeyService);
@@ -145,4 +150,9 @@ private String parseDid(String discriminator) {
145150
return uri.getPort() != 443 ? format("did:web:%s%%3A%s:%s", uri.getHost(), uri.getPort(), discriminator)
146151
: format("did:web:%s:%s", uri.getHost(), discriminator);
147152
}
153+
154+
public String getHolderPid() {
155+
return holderPid;
156+
}
157+
148158
}

0 commit comments

Comments
 (0)