Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
189 changes: 150 additions & 39 deletions README.md

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions config/tck/sample.tck.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# Contains sample configuration options
#dataspacetck.test.package=org.eclipse.dataspacetck.dcp.verification.presentation
dataspacetck.test.package=org.eclipse.dataspacetck.dcp.verification.issuance.issuer
dataspacetck.test.package=org.eclipse.dataspacetck.dcp.verification.presentation.verifier,org.eclipse.dataspacetck.dcp.verification.presentation.cs,org.eclipse.dataspacetck.dcp.verification.issuance.issuer,org.eclipse.dataspacetck.dcp.verification.presentation.issuance.cs
dataspacetck.credentials.correlation.id=foobar
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2025 Metaform Systems Inc.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Metaform Systems Inc. - initial API and implementation
*
*/

package org.eclipse.dataspacetck.dcp.system.annotation;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
* Used to inject a configurable endpoint at which the Verifier-Under-Test expects the DCP Presentation Flow to be kicked off.
*/
@Inherited
@Retention(RUNTIME)
@Target({ FIELD, PARAMETER })
public @interface TriggerEndpoint {
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,11 @@ public interface CredentialService {
* @return A collection of {@link VcContainer} objects representing the issued credentials.
*/
Collection<VcContainer> getCredentials();

/**
* Sets a delegate, which could be a mock, and which is used in place of the real credential service until set to null
*
* @param delegate a delegate
*/
void withDelegate(CredentialService delegate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,7 @@ public interface DcpConstants {

String CREDENTIAL_STATUS_PATH = "/requests/";

String NULL_BODY = "";

String JSON_CONTENT_TYPE = "application/json";
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import org.eclipse.dataspacetck.dcp.system.model.ExtensibleModel;
import org.eclipse.dataspacetck.dcp.system.service.Result;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;
import static org.eclipse.dataspacetck.dcp.system.service.Result.failure;

/**
* Models a DID document.
Expand Down Expand Up @@ -59,12 +61,13 @@ public ServiceEntry getServiceEntry(String type) {
.orElseThrow(() -> new IllegalArgumentException("No service found for type " + type));
}

public VerificationMethod getVerificationMethod(String id) {
public Result<VerificationMethod> getVerificationMethod(String id) {

return verificationMethods.stream()
.filter(m -> m.getId().equals(id) || m.getId().equals(this.id + id) || m.getId().equals(this.id + "#" + id))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No verification method found for id " + id));
.map(Result::success)
.orElseGet(() -> failure("No verification method found for id " + id));
}

@JsonPOJOBuilder(withPrefix = "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static java.util.Objects.requireNonNull;
Expand All @@ -34,7 +33,7 @@
public class MetadataReference {
private String id;
private String type;
private Map<String, Object> extensibleProperties = new LinkedHashMap<>();
private final Map<String, Object> extensibleProperties = new LinkedHashMap<>();

public String getId() {
return id;
Expand All @@ -51,7 +50,7 @@ public Map<String, Object> getExtensibleProperties() {
public Map<String, Object> toMap() {
var map = new LinkedHashMap<String, Object>();
map.put(ID, id);
map.put(TYPE, List.of(type));
map.put(TYPE, type);
map.putAll(extensibleProperties);
return map;
}
Expand All @@ -61,7 +60,7 @@ private MetadataReference() {

@JsonPOJOBuilder(withPrefix = "")
public static class Builder {
private MetadataReference reference;
private final MetadataReference reference;


@JsonCreator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@
public class VerifiableCredential extends ExtensibleModel {

private final List<String> type = new ArrayList<>();
private final Map<String, Object> credentialSubject = new LinkedHashMap<>();
private Map<String, Object> credentialSubject = new LinkedHashMap<>();
private String id;
private String issuer;
private String issuanceDate;
private String expirationDate;
private MetadataReference credentialSchema;
private MetadataReference credentialStatus;

Expand Down Expand Up @@ -82,6 +83,7 @@ public Map<String, Object> toMap() {
map.put(TYPE, type);
map.put("issuer", issuer);
map.put("issuanceDate", issuanceDate);
map.put("expirationDate", expirationDate);
if (credentialSchema != null) {
map.put("credentialSchema", credentialSchema);
}
Expand All @@ -95,6 +97,10 @@ public Map<String, Object> toMap() {
return map;
}

public String getExpirationDate() {
return expirationDate;
}

@JsonPOJOBuilder(withPrefix = "")
public static class Builder extends ExtensibleModel.Builder<Builder> {
private final VerifiableCredential credential;
Expand Down Expand Up @@ -129,6 +135,11 @@ public Builder issuanceDate(String date) {
return this;
}

public Builder expirationDate(String date) {
credential.expirationDate = date;
return this;
}

public Builder credentialSchema(MetadataReference credentialSchema) {
credential.credentialSchema = credentialSchema;
return this;
Expand All @@ -140,7 +151,7 @@ public Builder credentialStatus(MetadataReference status) {
}

public Builder credentialSubject(Map<String, Object> subject) {
credential.credentialSubject.putAll(subject);
credential.credentialSubject = subject;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ void verifyDeserializeSerialize() throws JsonProcessingException {
assertThat(deserialized.getServices()).allMatch(s -> s.id().equals("TCK-Credential-Service"));
assertThat(deserialized.getVerificationMethods()).allMatch(v -> v.getId().equals("43cecd95-7a59-4a5f-b2d0-0ec73ae41a0c"));
assertThat(deserialized.getVerificationMethod("43cecd95-7a59-4a5f-b2d0-0ec73ae41a0c")).isNotNull();
assertThat(deserialized.getVerificationMethod("43cecd95-7a59-4a5f-b2d0-0ec73ae41a0c").succeeded()).isTrue();
assertThat(deserialized.getServiceEntry("CredentialService")).isNotNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.dataspacetck.dcp.system.annotation.IssueCredentials;
import org.eclipse.dataspacetck.dcp.system.annotation.Issuer;
import org.eclipse.dataspacetck.dcp.system.annotation.ThirdParty;
import org.eclipse.dataspacetck.dcp.system.annotation.TriggerEndpoint;
import org.eclipse.dataspacetck.dcp.system.annotation.Verifier;
import org.eclipse.dataspacetck.dcp.system.assembly.BaseAssembly;
import org.eclipse.dataspacetck.dcp.system.assembly.ServiceAssembly;
Expand All @@ -34,6 +35,7 @@
import org.eclipse.dataspacetck.dcp.system.did.DidService;
import org.eclipse.dataspacetck.dcp.system.generation.JwtCredentialGenerator;
import org.eclipse.dataspacetck.dcp.system.model.vc.VcContainer;
import org.eclipse.dataspacetck.dcp.system.revocation.CredentialRevocationService;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
Expand All @@ -58,6 +60,7 @@ public void start(SystemConfiguration configuration) {
@Override
public <T> boolean providesService(Class<T> type) {
return type.isAssignableFrom(CredentialService.class) ||
type.isAssignableFrom(CredentialRevocationService.class) ||
type.isAssignableFrom(DidService.class) ||
type.isAssignableFrom(String.class) ||
type.isAssignableFrom(KeyService.class) ||
Expand All @@ -71,6 +74,8 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
var assembly = serviceAssemblies.computeIfAbsent(scopeId, id -> new ServiceAssembly(baseAssembly, resolver, configuration));
if (type.isAssignableFrom(CredentialService.class)) {
return type.cast(assembly.getCredentialService());
} else if (type.isAssignableFrom(CredentialRevocationService.class)) {
return type.cast(assembly.getRevocationService());
} else if (type.isAssignableFrom(VcContainer.class)) {
if (hasAnnotation(Credential.class, configuration)) {
var gen = new JwtCredentialGenerator(baseAssembly.getIssuerDid(), baseAssembly.getIssuerKeyService());
Expand Down Expand Up @@ -106,6 +111,9 @@ public <T> T getService(Class<T> type, ServiceConfiguration configuration, Servi
if (hasAnnotation(HolderPid.class, configuration)) {
return type.cast(baseAssembly.getHolderPid());
}
if (hasAnnotation(TriggerEndpoint.class, configuration)) {
return type.cast(baseAssembly.getVerifierTriggerEndpoint());
}

var did = getAnnotation(Did.class, configuration);
if (did.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,18 @@ public class BaseAssembly {
private final DidServiceImpl thirdPartyDidService;
private final ObjectMapper mapper;
private final String holderPid;
private final String verifierTriggerEndpoint;
private final String revocationListType;

public BaseAssembly(SystemConfiguration configuration) {
mapper = new ObjectMapper();
address = configuration.getPropertyAsString(TCK_CALLBACK_ADDRESS, TCK_DEFAULT_CALLBACK_ADDRESS);
verifierDid = parseDid("verifier");
var verifierDid = configuration.getPropertyAsString(TCK_PREFIX + ".did.verifier", null);
this.verifierDid = Objects.requireNonNullElseGet(verifierDid, () -> parseDid("verifier"));
var id = configuration.getPropertyAsString(TCK_PREFIX + ".did.issuer", null);
issuerDid = Objects.requireNonNullElseGet(id, () -> parseDid("issuer"));
thirdPartyDid = parseDid("thirdparty");
var did3p = configuration.getPropertyAsString(TCK_PREFIX + ".did.thirdparty", null);
this.thirdPartyDid = Objects.requireNonNullElseGet(did3p, () -> parseDid("thirdparty"));
issuerKeyService = new KeyServiceImpl(Keys.generateEcKey());
issuerDidService = new IssuerDidService(issuerDid, address, issuerKeyService);
issuerTokenService = new TokenValidationServiceImpl(issuerDid);
Expand All @@ -77,12 +81,19 @@ public BaseAssembly(SystemConfiguration configuration) {

holderPid = ofNullable(configuration.getPropertyAsString(TCK_PREFIX + ".credentials.correlation.id", null)).orElseGet(() -> randomUUID().toString());

verifierTokenService = new TokenValidationServiceImpl(verifierDid);
verifierTokenService = new TokenValidationServiceImpl(this.verifierDid);
verifierKeyService = new KeyServiceImpl(Keys.generateEcKey());
verifierDidService = new DidServiceImpl(verifierDid, address, verifierKeyService);
verifierDidService = new DidServiceImpl(this.verifierDid, address, verifierKeyService);
verifierTriggerEndpoint = Objects.requireNonNullElse(configuration.getPropertyAsString(TCK_PREFIX + ".vpp.trigger.endpoint", null), address + "/api/trigger");

thirdPartyKeyService = new KeyServiceImpl(Keys.generateEcKey());
thirdPartyDidService = new DidServiceImpl(thirdPartyDid, address, thirdPartyKeyService);

revocationListType = configuration.getPropertyAsString(TCK_PREFIX + ".revocation.type", "bitstringstatuslist");
}

public String getVerifierTriggerEndpoint() {
return verifierTriggerEndpoint;
}

public TokenValidationService getIssuerTokenService() {
Expand Down Expand Up @@ -153,14 +164,18 @@ public DidServiceImpl getThirdPartyDidService() {
return thirdPartyDidService;
}

public String getHolderPid() {
return holderPid;
}

public String getRevocationListType() {
return revocationListType;
}

private String parseDid(String discriminator) {
var uri = URI.create(address);
return uri.getPort() != 443 ? format("did:web:%s%%3A%s:%s", uri.getHost(), uri.getPort(), discriminator)
: format("did:web:%s:%s", uri.getHost(), discriminator);
}

public String getHolderPid() {
return holderPid;
}

}
Loading