Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add alias for issuance date #4254

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
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
import org.eclipse.edc.iam.verifiablecredentials.spi.model.CredentialStatus;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.provider.ArgumentsSource;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.model.HttpResponse;
import org.mockserver.verify.VerificationTimes;

import java.util.Map;
import java.util.stream.Stream;

import static org.eclipse.edc.iam.verifiablecredentials.spi.model.statuslist.StatusList2021Credential.STATUS_LIST_CREDENTIAL;
import static org.eclipse.edc.iam.verifiablecredentials.spi.model.statuslist.StatusList2021Credential.STATUS_LIST_INDEX;
Expand All @@ -45,19 +52,20 @@ class StatusList2021RevocationServiceTest {
void setup() {
clientAndServer = ClientAndServer.startClientAndServer("localhost", getFreePort());
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT));
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_INTERMEDIATE));
}

@AfterEach
void tearDown() {
clientAndServer.stop();
}

@Test
void checkRevocation_whenSubjectIsArray() {
@ParameterizedTest
@ArgumentsSource(ArraySubjectProvider.class)
void checkRevocation_whenSubjectIsArray(String testData) {
clientAndServer.reset();
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY));
.respond(HttpResponse.response().withStatusCode(200).withBody(testData));
var credential = TestFunctions.createCredentialBuilder().credentialStatus(new CredentialStatus("test-id", "StatusList2021",
Map.of(STATUS_LIST_PURPOSE, "revocation",
STATUS_LIST_INDEX, NOT_REVOKED_INDEX,
Expand Down Expand Up @@ -110,11 +118,12 @@ void checkRevocation_whenCached_valid() {
clientAndServer.verify(request(), VerificationTimes.exactly(1));
}

@Test
void getStatusPurposes_whenSingleCredentialStatusRevoked() {
@ParameterizedTest
@ArgumentsSource(SingleSubjectProvider.class)
void getStatusPurposes_whenSingleCredentialStatusRevoked(String testData) {
clientAndServer.reset();
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT));
.respond(HttpResponse.response().withStatusCode(200).withBody(testData));
var credential = TestFunctions.createCredentialBuilder().credentialStatus(new CredentialStatus("test-id", "StatusList2021",
Map.of(STATUS_LIST_PURPOSE, "revocation",
STATUS_LIST_INDEX, REVOKED_INDEX,
Expand All @@ -124,11 +133,12 @@ void getStatusPurposes_whenSingleCredentialStatusRevoked() {
.isEqualTo("revocation");
}

@Test
void getStatusPurposes_whenMultipleCredentialStatusRevoked() {
@ParameterizedTest
@ArgumentsSource(ArraySubjectProvider.class)
void getStatusPurposes_whenMultipleCredentialStatusRevoked(String testData) {
clientAndServer.reset();
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY));
.respond(HttpResponse.response().withStatusCode(200).withBody(testData));
var credential = TestFunctions.createCredentialBuilder().credentialStatus(new CredentialStatus("test-id", "StatusList2021",
Map.of(STATUS_LIST_PURPOSE, "revocation",
STATUS_LIST_INDEX, REVOKED_INDEX,
Expand All @@ -138,11 +148,12 @@ void getStatusPurposes_whenMultipleCredentialStatusRevoked() {
.isEqualTo("revocation");
}

@Test
void getStatusPurpose_whenCredentialStatusNotActive() {
@ParameterizedTest
@ArgumentsSource(SingleSubjectProvider.class)
void getStatusPurpose_whenCredentialStatusNotActive(String testData) {
clientAndServer.reset();
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT));
.respond(HttpResponse.response().withStatusCode(200).withBody(testData));
var credential = TestFunctions.createCredentialBuilder().credentialStatus(new CredentialStatus("test-id", "StatusList2021",
Map.of(STATUS_LIST_PURPOSE, "revocation",
STATUS_LIST_INDEX, NOT_REVOKED_INDEX,
Expand All @@ -152,15 +163,40 @@ void getStatusPurpose_whenCredentialStatusNotActive() {
.isNull();
}

@Test
void getStatusPurpose_whenNoCredentialStatus() {
@ParameterizedTest
@ArgumentsSource(SingleSubjectProvider.class)
void getStatusPurpose_whenNoCredentialStatus(String testData) {
clientAndServer.reset();
clientAndServer.when(request().withMethod("GET").withPath("/credentials/status/3"))
.respond(HttpResponse.response().withStatusCode(200).withBody(TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT));
.respond(HttpResponse.response().withStatusCode(200).withBody(testData));
var credential = TestFunctions.createCredentialBuilder().build();
assertThat(revocationService.getStatusPurpose(credential))
.isNotNull()
.isSucceeded();
}


private static class SingleSubjectProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
return Stream.of(
Arguments.of(Named.of("VC (intermediate)", TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_INTERMEDIATE)),
Arguments.of(Named.of("VC 1.1", TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_1_0)),
Arguments.of(Named.of("VC 2.0", TestData.STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_2_0))

);
}
}

private static class ArraySubjectProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) {
return Stream.of(
Arguments.of(Named.of("VC 1.1", TestData.STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_1_0)),
Arguments.of(Named.of("VC (intermediate)", TestData.STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_INTERMEDIATE)),
Arguments.of(Named.of("VC 2.0", TestData.STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_2_0))

);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

public class TestData {
// test data taken from https://www.w3.org/TR/2023/WD-vc-status-list-20230427/#example-example-statuslist2021credential-0
public static final String STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY = """
public static final String STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_INTERMEDIATE = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
Expand All @@ -37,7 +37,7 @@ public class TestData {
}
""";

public static final String STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT = """
public static final String STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_INTERMEDIATE = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
Expand All @@ -55,4 +55,85 @@ public class TestData {
}
}
""";

public static final String STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_2_0 = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc/status-list/2021/v1"
],
"id": "https://example.com/credentials/status/3",
"type": ["VerifiableCredential", "StatusList2021Credential"],
"issuer": "did:example:12345",
"validFrom": "2021-04-05T14:27:40Z",
"credentialSubject": [
{
"id": "https://example.com/status/3#list",
"type": "StatusList2021",
"https://w3id.org/vc/status-list#statusPurpose": "revocation",
"https://w3id.org/vc/status-list#encodedList": "H4sIAAAAAAAAA+3BIQEAAAACIP+vcKozLEADAAAAAAAAAAAAAAAAAAAAvA0cOP65AEAAAA"
}
]
}
""";

public static final String STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_2_0 = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc/status-list/2021/v1"
],
"id": "https://example.com/credentials/status/3",
"type": ["VerifiableCredential", "StatusList2021Credential"],
"issuer": "did:example:12345",
"validFrom": "2021-04-05T14:27:40Z",
"credentialSubject": {
"id": "https://example.com/status/3#list",
"type": "StatusList2021",
"https://w3id.org/vc/status-list#statusPurpose": "revocation",
"https://w3id.org/vc/status-list#encodedList": "H4sIAAAAAAAAA+3BIQEAAAACIP+vcKozLEADAAAAAAAAAAAAAAAAAAAAvA0cOP65AEAAAA"
}
}
""";


public static final String STATUS_LIST_CREDENTIAL_SUBJECT_IS_ARRAY_1_0 = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc/status-list/2021/v1"
],
"id": "https://example.com/credentials/status/3",
"type": ["VerifiableCredential", "StatusList2021Credential"],
"issuer": "did:example:12345",
"issuanceDate": "2021-04-05T14:27:40Z",
"credentialSubject": [
{
"id": "https://example.com/status/3#list",
"type": "StatusList2021",
"https://w3id.org/vc/status-list#statusPurpose": "revocation",
"https://w3id.org/vc/status-list#encodedList": "H4sIAAAAAAAAA+3BIQEAAAACIP+vcKozLEADAAAAAAAAAAAAAAAAAAAAvA0cOP65AEAAAA"
}
]
}
""";

public static final String STATUS_LIST_CREDENTIAL_SINGLE_SUBJECT_1_0 = """
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://w3id.org/vc/status-list/2021/v1"
],
"id": "https://example.com/credentials/status/3",
"type": ["VerifiableCredential", "StatusList2021Credential"],
"issuer": "did:example:12345",
"issuanceDate": "2021-04-05T14:27:40Z",
"credentialSubject": {
"id": "https://example.com/status/3#list",
"type": "StatusList2021",
"https://w3id.org/vc/status-list#statusPurpose": "revocation",
"https://w3id.org/vc/status-list#encodedList": "H4sIAAAAAAAAA+3BIQEAAAACIP+vcKozLEADAAAAAAAAAAAAAAAAAAAAvA0cOP65AEAAAA"
}
}
""";
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ public Issuer getIssuer() {
return issuer;
}

@JsonAlias({ "issued" }) // some credentials like StatusList2021 don't adhere to the spec
@JsonAlias({ "issued", "validFrom" }) // some credentials like StatusList2021 don't adhere to the spec
@NotNull
public Instant getIssuanceDate() {
return issuanceDate;
}

@JsonAlias({ "validUntil" })
public Instant getExpirationDate() {
return expirationDate;
}
Expand Down
Loading