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: implement PresentationGenerator #172

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
14 changes: 7 additions & 7 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
maven/mavencentral/com.apicatalog/carbon-did/0.0.2, Apache-2.0, approved, #9239

Check warning on line 1 in DEPENDENCIES

View workflow job for this annotation

GitHub Actions / check / Dash-Verify-Licenses

Restricted Dependencies found

Some dependencies are marked 'restricted' - please review them
maven/mavencentral/com.apicatalog/iron-ed25519-cryptosuite-2020/0.8.1, Apache-2.0, approved, #11157
maven/mavencentral/com.apicatalog/iron-verifiable-credentials/0.8.1, Apache-2.0, approved, #9234
maven/mavencentral/com.apicatalog/titanium-json-ld/1.0.0, Apache-2.0, approved, clearlydefined
Expand Down Expand Up @@ -138,24 +138,24 @@
maven/mavencentral/io.swagger.core.v3/swagger-core-jakarta/2.2.18, Apache-2.0, approved, #5929
maven/mavencentral/io.swagger.core.v3/swagger-core/2.2.15, Apache-2.0, approved, #9265
maven/mavencentral/io.swagger.core.v3/swagger-core/2.2.8, Apache-2.0, approved, #9265
maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.15, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.18, , restricted, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.15, Apache-2.0, approved, #11475
maven/mavencentral/io.swagger.core.v3/swagger-integration-jakarta/2.2.18, Apache-2.0, approved, #11475
maven/mavencentral/io.swagger.core.v3/swagger-integration/2.2.15, Apache-2.0, approved, #10352
maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.15, Apache-2.0, approved, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.18, , restricted, clearlydefined
maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.15, Apache-2.0, approved, #11477
maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2-jakarta/2.2.18, Apache-2.0, approved, #11477
maven/mavencentral/io.swagger.core.v3/swagger-jaxrs2/2.2.15, Apache-2.0, approved, #9814
maven/mavencentral/io.swagger.core.v3/swagger-models-jakarta/2.2.15, Apache-2.0, approved, #5919
maven/mavencentral/io.swagger.core.v3/swagger-models-jakarta/2.2.18, Apache-2.0, approved, #5919
maven/mavencentral/io.swagger.core.v3/swagger-models/2.2.15, Apache-2.0, approved, #10353
maven/mavencentral/io.swagger.core.v3/swagger-models/2.2.8, Apache-2.0, approved, #10353
maven/mavencentral/io.swagger.parser.v3/swagger-parser-core/2.1.10, None, restricted, #11314
maven/mavencentral/io.swagger.parser.v3/swagger-parser-core/2.1.10, None, restricted, #11478
maven/mavencentral/io.swagger.parser.v3/swagger-parser-v2-converter/2.1.10, Apache-2.0, approved, #9330
maven/mavencentral/io.swagger.parser.v3/swagger-parser-v3/2.1.10, Apache-2.0, approved, #9323
maven/mavencentral/io.swagger.parser.v3/swagger-parser/2.1.10, None, restricted, #11316
maven/mavencentral/io.swagger/swagger-annotations/1.6.9, Apache-2.0, approved, #3792
maven/mavencentral/io.swagger/swagger-compat-spec-parser/1.0.64, None, restricted, #11282
maven/mavencentral/io.swagger/swagger-compat-spec-parser/1.0.64, None, restricted, #11479
maven/mavencentral/io.swagger/swagger-core/1.6.9, Apache-2.0, approved, #4358
maven/mavencentral/io.swagger/swagger-models/1.6.9, LicenseRef-scancode-proprietary-license, restricted, #11330
maven/mavencentral/io.swagger/swagger-models/1.6.9, LicenseRef-scancode-proprietary-license, restricted, #11476
maven/mavencentral/io.swagger/swagger-parser/1.0.64, Apache-2.0, approved, #4359
maven/mavencentral/jakarta.activation/jakarta.activation-api/1.2.1, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf
maven/mavencentral/jakarta.activation/jakarta.activation-api/2.1.0, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf
Expand Down
8 changes: 8 additions & 0 deletions core/identity-hub-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ dependencies {
api(project(":spi:identity-hub-store-spi"))
implementation(libs.edc.core.connector) // for the CriterionToPredicateConverterImpl
implementation(libs.edc.spi.jsonld)
implementation(libs.edc.spi.jsonld)
implementation(libs.edc.ext.jsonld) // for the JSON-LD mapper
implementation(libs.edc.iatp.service) // JWT validator
implementation(libs.edc.core.crypto) // JWT verifier
implementation(libs.edc.jws2020)
implementation(libs.edc.vc.ldp)
implementation(libs.edc.util)
implementation(libs.nimbus.jwt)

testImplementation(libs.edc.junit)
testImplementation(libs.edc.ext.jsonld)
testImplementation(testFixtures(project(":spi:identity-hub-spi")))
testImplementation(testFixtures(libs.edc.vc.jwt)) // JWT generator
testImplementation(libs.edc.identity.did.crypto) // EC private key wrapper
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,39 @@

package org.eclipse.edc.identityhub;

import com.apicatalog.ld.signature.SignatureSuite;
import org.eclipse.edc.identityhub.defaults.EdcScopeToCriterionTransformer;
import org.eclipse.edc.identityhub.defaults.InMemoryCredentialStore;
import org.eclipse.edc.identityhub.spi.ScopeToCriterionTransformer;
import org.eclipse.edc.identityhub.spi.generator.PresentationGenerator;
import org.eclipse.edc.identityhub.spi.model.IdentityHubConstants;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
import org.eclipse.edc.identitytrust.verification.SignatureSuiteRegistry;
import org.eclipse.edc.jsonld.util.JacksonJsonLd;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.security.signature.jws2020.JwsSignature2020Suite;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;

@Extension("Default Services Extension")
import java.util.Collection;
import java.util.Map;

import static org.eclipse.edc.identityhub.DefaultServicesExtension.NAME;

@Extension(NAME)
public class DefaultServicesExtension implements ServiceExtension {
@Provider(isDefault = true)
public CredentialStore createInMemStore() {
return new InMemoryCredentialStore();

public static final String NAME = "IdentityHub Default Services Extension";

@Override
public String name() {
return NAME;
}

@Provider(isDefault = true)
public PresentationGenerator createPresentationGenerator(ServiceExtensionContext context) {
context.getMonitor().warning(" #### Creating a default NOOP PresentationGenerator, that will always return 'null'!");
return (credentials, presentationDefinition) -> null;
public CredentialStore createInMemStore() {
return new InMemoryCredentialStore();

}

@Provider(isDefault = true)
Expand All @@ -45,4 +56,25 @@ public ScopeToCriterionTransformer createScopeTransformer(ServiceExtensionContex
return new EdcScopeToCriterionTransformer();
}

@Provider(isDefault = true)
public SignatureSuiteRegistry createSignatureSuiteRegistry() {
return new SignatureSuiteRegistry() {
private final Map<String, SignatureSuite> registry = Map.of(IdentityHubConstants.JWS_2020_SIGNATURE_SUITE, new JwsSignature2020Suite(JacksonJsonLd.createObjectMapper()));

@Override
public void register(String w3cIdentifier, SignatureSuite suite) {

}

@Override
public SignatureSuite getForId(String w3cIdentifier) {
return registry.get(w3cIdentifier);
}

@Override
public Collection<SignatureSuite> getAllSuites() {
return registry.values();
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,83 @@
import org.eclipse.edc.iam.did.spi.key.PublicKeyWrapper;
import org.eclipse.edc.iam.did.spi.resolution.DidResolverRegistry;
import org.eclipse.edc.iam.identitytrust.validation.SelfIssuedIdTokenValidator;
import org.eclipse.edc.identityhub.core.creators.JwtPresentationCreator;
import org.eclipse.edc.identityhub.core.creators.LdpPresentationCreator;
import org.eclipse.edc.identityhub.spi.ScopeToCriterionTransformer;
import org.eclipse.edc.identityhub.spi.generator.PresentationCreatorRegistry;
import org.eclipse.edc.identityhub.spi.generator.PresentationGenerator;
import org.eclipse.edc.identityhub.spi.model.IdentityHubConstants;
import org.eclipse.edc.identityhub.spi.resolution.CredentialQueryResolver;
import org.eclipse.edc.identityhub.spi.store.CredentialStore;
import org.eclipse.edc.identityhub.spi.verification.AccessTokenVerifier;
import org.eclipse.edc.identityhub.token.verification.AccessTokenVerifierImpl;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.validation.JwtValidator;
import org.eclipse.edc.identitytrust.verification.JwtVerifier;
import org.eclipse.edc.identitytrust.verification.SignatureSuiteRegistry;
import org.eclipse.edc.jsonld.spi.JsonLd;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Inject;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.runtime.metamodel.annotation.Setting;
import org.eclipse.edc.spi.security.PrivateKeyResolver;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.verifiablecredentials.linkeddata.LdpIssuer;
import org.eclipse.edc.verification.jwt.SelfIssuedIdTokenVerifier;

import java.net.URISyntaxException;
import java.time.Clock;

import static org.eclipse.edc.identityhub.core.CoreServicesExtension.NAME;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.DID_CONTEXT_URL;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.IATP_CONTEXT_URL;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.JWS_2020_URL;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.PRESENTATION_EXCHANGE_URL;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.PRESENTATION_SUBMISSION_URL;
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.W3C_CREDENTIALS_URL;

/**
* This extension provides some core services for the IdentityHub, such as:
* <ul>
* <li>an {@link AccessTokenVerifier}</li>
* <li>a {@link JwtValidator}</li>
* <li>a {@link JwtVerifier}</li>
* </ul>
* This extension provides core services for the IdentityHub that are not intended to be user-replaceable.
*/
@Extension(value = "Core Services extension")
@Extension(value = NAME)
public class CoreServicesExtension implements ServiceExtension {

public static final String NAME = "IdentityHub Core Services Extension";
@Setting(value = "Configure this IdentityHub's DID", required = true)
public static final String OWN_DID_PROPERTY = "edc.ih.iam.id";
public static final String PRESENTATION_EXCHANGE_V_1_JSON = "presentation-exchange.v1.json";
public static final String PRESENTATION_QUERY_V_08_JSON = "presentation-query.v08.json";
public static final String PRESENTATION_SUBMISSION_V1_JSON = "presentation-submission.v1.json";
public static final String DID_JSON = "did.json";
public static final String JWS_2020_JSON = "jws2020.json";
public static final String CREDENTIALS_V_1_JSON = "credentials.v1.json";
private final String defaultSuite = IdentityHubConstants.JWS_2020_SIGNATURE_SUITE;
private PresentationCreatorRegistryImpl presentationCreatorRegistry;
private JwtVerifier jwtVerifier;
private JwtValidator jwtValidator;

@Inject
private DidResolverRegistry didResolverRegistry;

@Inject
private PublicKeyWrapper identityHubPublicKey;

@Inject
private JsonLd jsonLd;

@Inject
private CredentialStore credentialStore;

@Inject
private ScopeToCriterionTransformer transformer;
@Inject
private PrivateKeyResolver privateKeyResolver;
@Inject
private Clock clock;
@Inject
private SignatureSuiteRegistry signatureSuiteRegistry;

@Override
public String name() {
return NAME;
}

@Override
public void initialize(ServiceExtensionContext context) {
Expand Down Expand Up @@ -102,6 +127,25 @@ public CredentialQueryResolver createCredentialQueryResolver() {
return new CredentialQueryResolverImpl(credentialStore, transformer);
}

@Provider
public PresentationCreatorRegistry presentationCreatorRegistry(ServiceExtensionContext context) {
if (presentationCreatorRegistry == null) {
presentationCreatorRegistry = new PresentationCreatorRegistryImpl();
presentationCreatorRegistry.addCreator(new JwtPresentationCreator(privateKeyResolver, clock, getOwnDid(context)), CredentialFormat.JWT);

var ldpIssuer = LdpIssuer.Builder.newInstance().jsonLd(jsonLd).monitor(context.getMonitor()).build();
presentationCreatorRegistry.addCreator(new LdpPresentationCreator(privateKeyResolver, getOwnDid(context), signatureSuiteRegistry, defaultSuite, ldpIssuer, null),
CredentialFormat.JSON_LD);
}
return presentationCreatorRegistry;
}

@Provider
public PresentationGenerator presentationGenerator(ServiceExtensionContext context) {
return new PresentationGeneratorImpl(CredentialFormat.JSON_LD, presentationCreatorRegistry, context.getMonitor());
}


private String getOwnDid(ServiceExtensionContext context) {
return context.getConfig().getString(OWN_DID_PROPERTY);
}
Expand All @@ -110,6 +154,10 @@ private void cacheContextDocuments(ClassLoader classLoader) {
try {
jsonLd.registerCachedDocument(PRESENTATION_EXCHANGE_URL, classLoader.getResource(PRESENTATION_EXCHANGE_V_1_JSON).toURI());
jsonLd.registerCachedDocument(IATP_CONTEXT_URL, classLoader.getResource(PRESENTATION_QUERY_V_08_JSON).toURI());
jsonLd.registerCachedDocument(DID_CONTEXT_URL, classLoader.getResource(DID_JSON).toURI());
jsonLd.registerCachedDocument(JWS_2020_URL, classLoader.getResource(JWS_2020_JSON).toURI());
jsonLd.registerCachedDocument(W3C_CREDENTIALS_URL, classLoader.getResource(CREDENTIALS_V_1_JSON).toURI());
jsonLd.registerCachedDocument(PRESENTATION_SUBMISSION_URL, classLoader.getResource(PRESENTATION_SUBMISSION_V1_JSON).toURI());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
*
* 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:
* Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation
*
*/

package org.eclipse.edc.identityhub.core;

import org.eclipse.edc.identityhub.spi.generator.PresentationCreator;
import org.eclipse.edc.identityhub.spi.generator.PresentationCreatorRegistry;
import org.eclipse.edc.identitytrust.model.CredentialFormat;
import org.eclipse.edc.identitytrust.model.VerifiableCredentialContainer;
import org.eclipse.edc.spi.EdcException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Optional.ofNullable;

public class PresentationCreatorRegistryImpl implements PresentationCreatorRegistry {

private final Map<CredentialFormat, PresentationCreator<?>> creators = new HashMap<>();
private final Map<CredentialFormat, String> keyIds = new HashMap<>();

@Override
public void addCreator(PresentationCreator<?> creator, CredentialFormat format) {
creators.put(format, creator);
}

@Override
public <T> T createPresentation(List<VerifiableCredentialContainer> credentials, CredentialFormat format) {
var creator = ofNullable(creators.get(format)).orElseThrow(() -> new EdcException("No PresentationCreator was found for CredentialFormat %s".formatted(format)));
var keyId = ofNullable(keyIds.get(format)).orElseThrow(() -> new EdcException("No key ID was registered for CredentialFormat %s".formatted(format)));

return (T) creator.createPresentation(credentials, keyId);
}

@Override
public void addKeyId(String keyId, CredentialFormat format) {
keyIds.put(format, keyId);
}
}
Loading
Loading