-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add the Resolution API (stubbed) * PR remarks
- Loading branch information
1 parent
31c6df8
commit 4c5d327
Showing
192 changed files
with
2,284 additions
and
9,126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/* | ||
* 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 | ||
* | ||
*/ | ||
|
||
plugins { | ||
`java-library` | ||
`maven-publish` | ||
id("io.swagger.core.v3.swagger-gradle-plugin") | ||
} | ||
|
||
dependencies { | ||
api(libs.edc.spi.jsonld) | ||
api(libs.edc.spi.core) | ||
api(project(":spi:identity-hub-spi")) | ||
implementation(project(":core:identity-hub-transform")) | ||
implementation(libs.edc.spi.validator) | ||
implementation(libs.edc.spi.web) | ||
implementation(libs.edc.core.jerseyproviders) | ||
implementation(libs.edc.core.transform) | ||
implementation(libs.jakarta.rsApi) | ||
testImplementation(libs.edc.junit) | ||
testImplementation(libs.edc.ext.jsonld) | ||
testImplementation(testFixtures(libs.edc.core.jersey)) | ||
testImplementation(testFixtures(project(":spi:identity-hub-spi"))) | ||
testImplementation(libs.nimbus.jwt) | ||
} |
102 changes: 102 additions & 0 deletions
102
...y-hub-api/src/main/java/org/eclipse/edc/identityservice/api/PresentationApiExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* | ||
* 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.identityservice.api; | ||
|
||
import org.eclipse.edc.core.transform.transformer.to.JsonValueToGenericTypeTransformer; | ||
import org.eclipse.edc.identityhub.spi.generator.PresentationGenerator; | ||
import org.eclipse.edc.identityhub.spi.model.PresentationQuery; | ||
import org.eclipse.edc.identityhub.spi.resolution.CredentialQueryResolver; | ||
import org.eclipse.edc.identityhub.spi.verification.AccessTokenVerifier; | ||
import org.eclipse.edc.identityhub.transform.JsonObjectToPresentationQueryTransformer; | ||
import org.eclipse.edc.identityservice.api.v1.PresentationApiController; | ||
import org.eclipse.edc.identityservice.api.validation.PresentationQueryValidator; | ||
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.spi.system.ServiceExtension; | ||
import org.eclipse.edc.spi.system.ServiceExtensionContext; | ||
import org.eclipse.edc.spi.types.TypeManager; | ||
import org.eclipse.edc.transform.spi.TypeTransformerRegistry; | ||
import org.eclipse.edc.validator.spi.JsonObjectValidatorRegistry; | ||
import org.eclipse.edc.web.jersey.jsonld.JerseyJsonLdInterceptor; | ||
import org.eclipse.edc.web.jersey.jsonld.ObjectMapperProvider; | ||
import org.eclipse.edc.web.spi.WebService; | ||
|
||
import java.net.URISyntaxException; | ||
|
||
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.IATP_CONTEXT_URL; | ||
import static org.eclipse.edc.identityhub.spi.model.IdentityHubConstants.PRESENTATION_EXCHANGE_URL; | ||
import static org.eclipse.edc.spi.CoreConstants.JSON_LD; | ||
|
||
@Extension(value = "Presentation API Extension") | ||
public class PresentationApiExtension implements ServiceExtension { | ||
|
||
public static final String RESOLUTION_SCOPE = "resolution-scope"; | ||
public static final String RESOLUTION_CONTEXT = "resolution"; | ||
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"; | ||
@Inject | ||
private TypeTransformerRegistry typeTransformer; | ||
|
||
@Inject | ||
private JsonObjectValidatorRegistry validatorRegistry; | ||
|
||
@Inject | ||
private WebService webService; | ||
|
||
@Inject | ||
private AccessTokenVerifier accessTokenVerifier; | ||
|
||
@Inject | ||
private CredentialQueryResolver credentialResolver; | ||
|
||
@Inject | ||
private PresentationGenerator presentationGenerator; | ||
|
||
@Inject | ||
private JsonLd jsonLd; | ||
|
||
@Inject | ||
private TypeManager typeManager; | ||
|
||
@Override | ||
public void initialize(ServiceExtensionContext context) { | ||
// setup validator | ||
validatorRegistry.register(PresentationQuery.PRESENTATION_QUERY_TYPE_PROPERTY, new PresentationQueryValidator()); | ||
|
||
|
||
// Setup API | ||
cacheContextDocuments(getClass().getClassLoader()); | ||
var controller = new PresentationApiController(validatorRegistry, typeTransformer, credentialResolver, accessTokenVerifier, presentationGenerator, context.getMonitor()); | ||
|
||
var jsonLdMapper = typeManager.getMapper(JSON_LD); | ||
webService.registerResource(RESOLUTION_CONTEXT, new ObjectMapperProvider(jsonLdMapper)); | ||
webService.registerResource(RESOLUTION_CONTEXT, new JerseyJsonLdInterceptor(jsonLd, jsonLdMapper, RESOLUTION_SCOPE)); | ||
webService.registerResource(RESOLUTION_CONTEXT, controller); | ||
|
||
// register transformer | ||
typeTransformer.register(new JsonObjectToPresentationQueryTransformer(jsonLdMapper)); | ||
typeTransformer.register(new JsonValueToGenericTypeTransformer(jsonLdMapper)); | ||
} | ||
|
||
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()); | ||
} catch (URISyntaxException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} |
112 changes: 112 additions & 0 deletions
112
core/identity-hub-api/src/main/java/org/eclipse/edc/identityservice/api/v1/ApiSchema.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* 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.identityservice.api.v1; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
|
||
import java.util.List; | ||
|
||
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED; | ||
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; | ||
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; | ||
import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; | ||
|
||
public interface ApiSchema { | ||
@Schema(name = "ApiErrorDetail", example = ApiErrorDetailSchema.API_ERROR_EXAMPLE) | ||
record ApiErrorDetailSchema( | ||
String message, | ||
String type, | ||
String path, | ||
String invalidValue | ||
) { | ||
public static final String API_ERROR_EXAMPLE = """ | ||
{ | ||
"message": "error message", | ||
"type": "ErrorType", | ||
"path": "object.error.path", | ||
"invalidValue": "this value is not valid" | ||
} | ||
"""; | ||
} | ||
|
||
@Schema(name = "PresentationQuerySchema", example = PresentationQuerySchema.PRESENTATION_QUERY_EXAMPLE) | ||
record PresentationQuerySchema( | ||
@Schema(name = CONTEXT, requiredMode = REQUIRED) | ||
Object context, | ||
@Schema(name = TYPE, requiredMode = REQUIRED) | ||
String type, | ||
@Schema(name = "scope", requiredMode = NOT_REQUIRED) | ||
List<String> scope, | ||
@Schema(name = "presentation_definition", requiredMode = NOT_REQUIRED) | ||
PresentationDefinitionSchema presentationDefinitionSchema | ||
) { | ||
|
||
public static final String PRESENTATION_QUERY_EXAMPLE = """ | ||
{ | ||
"@context": [ | ||
"https://w3id.org/yourdataspace/2023/cs/v1", | ||
"https://identity.foundation/presentation-exchange/submission/v1" | ||
], | ||
"@type": "Query", | ||
"presentation_definition": null, | ||
"scope": [ | ||
"org.eclipse.edc.vc.type:SomeCredential_0.3.5:write, | ||
"org.eclipse.edc.vc.type:SomeOtherCredential:read, | ||
"org.eclipse.edc.vc.type:ThirdCredential:*, | ||
] | ||
} | ||
"""; | ||
} | ||
|
||
@Schema(name = "PresentationResponse", example = PresentationResponse.RESPONSE_EXAMPLE) | ||
record PresentationResponse() { | ||
|
||
public static final String RESPONSE_EXAMPLE = """ | ||
"""; | ||
} | ||
|
||
@Schema(name = "PresentationDefinitionSchema", example = PresentationDefinitionSchema.EXAMPLE) | ||
record PresentationDefinitionSchema() { | ||
|
||
private static final String EXAMPLE = """ | ||
{ | ||
"comment": "taken from https://identity.foundation/presentation-exchange/spec/v2.0.0/#presentation-definition" | ||
"presentation_definition": { | ||
"id": "first simple example", | ||
"input_descriptors": [ | ||
{ | ||
"id": "A specific type of VC", | ||
"name": "A specific type of VC", | ||
"purpose": "We want a VC of this type", | ||
"constraints": { | ||
"fields": [ | ||
{ | ||
"path": [ | ||
"$.type" | ||
], | ||
"filter": { | ||
"type": "string", | ||
"pattern": "<the type of VC e.g. degree certificate>" | ||
} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
} | ||
"""; | ||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
...dentity-hub-api/src/main/java/org/eclipse/edc/identityservice/api/v1/PresentationApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/* | ||
* 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.identityservice.api.v1; | ||
|
||
|
||
import io.swagger.v3.oas.annotations.OpenAPIDefinition; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn; | ||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; | ||
import io.swagger.v3.oas.annotations.info.Info; | ||
import io.swagger.v3.oas.annotations.media.ArraySchema; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.parameters.RequestBody; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.security.SecurityScheme; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import jakarta.json.JsonObject; | ||
import jakarta.ws.rs.core.Response; | ||
import org.eclipse.edc.identityhub.spi.model.PresentationResponse; | ||
import org.eclipse.edc.identityservice.api.v1.ApiSchema.ApiErrorDetailSchema; | ||
|
||
@OpenAPIDefinition( | ||
info = @Info(description = "This represents the Presentation API as per IATP specification. It serves endpoints to query for specific VerifiablePresentations.", title = "Resolution API", | ||
version = "1")) | ||
@SecurityScheme(name = "Authentication", | ||
description = "Self-Issued ID token containing an access_token", | ||
type = SecuritySchemeType.HTTP, | ||
scheme = "Bearer", | ||
bearerFormat = "JWT", | ||
in = SecuritySchemeIn.HEADER) | ||
public interface PresentationApi { | ||
|
||
@Tag(name = "Resolution API") | ||
@Operation(description = "Issues a new presentation query, that contains either a DIF presentation definition, or a list of scopes", | ||
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = ApiSchema.PresentationQuerySchema.class), mediaType = "application/ld+json")), | ||
responses = { | ||
@ApiResponse(responseCode = "200", description = "The query was successfully processed, the response contains the VerifiablePresentation", | ||
content = @Content(schema = @Schema(implementation = PresentationResponse.class), mediaType = "application/ld+json")), | ||
@ApiResponse(responseCode = "400", description = "Request body was malformed, for example when both scope and presentation_definition are given", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetailSchema.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "401", description = "No Authorization header was given.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetailSchema.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "403", description = "The given authentication token could not be validated. This can happen, when the request body " + | ||
"calls for a broader query scope than the granted scope in the auth token", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetailSchema.class)), mediaType = "application/json")), | ||
@ApiResponse(responseCode = "501", description = "When the request contained a presentation_definition object, but the implementation does not support it.", | ||
content = @Content(array = @ArraySchema(schema = @Schema(implementation = ApiErrorDetailSchema.class)), mediaType = "application/json")) | ||
} | ||
) | ||
Response queryPresentation(JsonObject query, String authHeader); | ||
} |
Oops, something went wrong.