diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/apidocs/IssuersCredentialControllerApiDocs.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/apidocs/IssuersCredentialControllerApiDocs.java index 200f78e8f..37b43f503 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/apidocs/IssuersCredentialControllerApiDocs.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/apidocs/IssuersCredentialControllerApiDocs.java @@ -202,7 +202,8 @@ public class IssuersCredentialControllerApiDocs { @RequestBody(content = { @Content(examples = @ExampleObject(""" { - "bpn": "BPNL000000000000" + "bpn": "BPNL000000000000", + "asJwt": false } """)) }) @@ -329,7 +330,8 @@ public class IssuersCredentialControllerApiDocs { "activityType": "vehicleDismantle", "allowedVehicleBrands": [ "Audi", "Abarth", "Alfa Romeo", "Chrysler" - ] + ], + "asJwt": false } """)) }) @@ -461,7 +463,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "BehaviorTwinCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "PcfCredential", value = """ @@ -469,7 +472,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "PcfCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "SustainabilityCredential", value = """ @@ -477,7 +481,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "SustainabilityCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "QualityCredential", value = """ @@ -485,7 +490,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "QualityCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "TraceabilityCredential", value = """ @@ -493,7 +499,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "TraceabilityCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "BehaviorTwinCredential", value = """ @@ -501,7 +508,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "BehaviorTwinCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """), @ExampleObject(name = "ResiliencyCredential", value = """ @@ -509,7 +517,8 @@ public class IssuersCredentialControllerApiDocs { "holderIdentifier": "BPNL000000000000", "type": "ResiliencyCredential", "contract-template": "https://public.catena-x.org/contracts/traceabilty.v1.pdf", - "contract-version": "1.0.0" + "contract-version": "1.0.0", + "asJwt": false } """) @@ -908,45 +917,101 @@ public class IssuersCredentialControllerApiDocs { } } """), + @ExampleObject(name = "Revocable Verifiable credentials with check expiry ", value = """ + { + "credentialStatus": "active", + "valid": true, + "validateExpiryDate": true, + "vc": { + "credentialSubject": [ + { + "holderIdentifier": "BPNL000000000001", + "allowedVehicleBrands": [ + "Audi", + "Abarth", + "Alfa Romeo", + "Chrysler" + ], + "id": "did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000001", + "activityType": "vehicleDismantle", + "type": "DismantlerCredential" + } + ], + "issuanceDate": "2024-01-05T05:42:53Z", + "id": "did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000000#8507aa50-b2a4-4532-8e45-f50e7654b23b", + "proof": { + "proofPurpose": "assertionMethod", + "verificationMethod": "did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000000#a39d8ccf-2a66-488d-bfec-916768082e91", + "type": "JsonWebSignature2020", + "created": "2024-01-05T05:42:53Z", + "jws": "eyJhbGciOiJFZERTQSJ9..15NdxA8L_Iw7Igxevm7YGMAQA-Kt6PMOpix6p0jaYHCtfQnTy3q61SDvsnsltGT6fzM90JOubOuig2WFy-GPDg" + }, + "type": [ + "VerifiableCredential", + "DismantlerCredential" + ], + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://cofinity-x.github.io/schema-registry/v1.1/DismantlerVC.json", + "https://w3id.org/security/suites/jws-2020/v1", + "https://w3id.org/vc/status-list/2021/v1" + ], + "issuer": "did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000000", + "credentialStatus": { + "id": "did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000000#0", + "statusPurpose": "revocation", + "statusListIndex": "0", + "statusListCredential": "https://ae96-203-129-213-107.ngrok-free.app/api/v1/revocations/credentials?issuerId=did:web:6e3e-203-129-213-107.ngrok-free.app:BPNL000000000000", + "type": "StatusList2021Entry" + }, + "expirationDate": "2024-12-31T18:30:00Z" + } + } + """), @ExampleObject(name = "Verifiable Credentials with invalid signature", value = """ { - "valid": false, - "vc": { - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json", - "https://w3id.org/security/suites/jws-2020/v1" - ], - "id": "did:web:localhost:BPNL000000000000#f73e3631-ba87-4a03-bea3-b28700056879", - "type": [ - "VerifiableCredential", - "BpnCredential" - ], - "issuer": "did:web:localhost:BPNL000000000000", - "expirationDate": "2024-12-31T18:30:00Z" - "issuanceDate": "2023-07-19T09:11:34Z", - "credentialSubject": [ - { - "bpn": "BPNL000000000000", - "id": "did:web:localhost:BPNL000000000000", - "type": "BpnCredential" - } - ], - "proof": { - "created": "2023-07-19T09:11:39Z", - "jws": "eyJhbGciOiJFZERTQSJ9..fdn2qU85auOltdHDLdHI7sJVV1ZPdftpiXd_ndXN0dFgSDWiIrScdD03wtvKLq_H-shQWfh2RYeMmrlEzAhf", - "proofPurpose": "proofPurpose", - "type": "JsonWebSignature2020", - "verificationMethod": "did:web:localhost:BPNL000000000000#" - }, - } + "valid": false, + "vc": + { + "@context": + [ + "https://www.w3.org/2018/credentials/v1", + "https://catenax-ng.github.io/product-core-schemas/businessPartnerData.json", + "https://w3id.org/security/suites/jws-2020/v1" + ], + "id": "did:web:localhost:BPNL000000000000#f73e3631-ba87-4a03-bea3-b28700056879", + "type": + [ + "VerifiableCredential", + "BpnCredential" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T18:30:00Z", + "issuanceDate": "2023-07-19T09:11:34Z", + "credentialSubject": + [ + { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + } + ], + "proof": + { + "created": "2023-07-19T09:11:39Z", + "jws": "eyJhbGciOiJFZERTQSJ9..fdn2qU85auOltdHDLdHI7sJVV1ZPdftpiXd_ndXN0dFgSDWiIrScdD03wtvKLq_H-shQWfh2RYeMmrlEzAhf", + "proofPurpose": "proofPurpose", + "type": "JsonWebSignature2020", + "verificationMethod": "did:web:localhost:BPNL000000000000#" + } + } } """) }) }) }) @Operation(summary = "Validate Verifiable Credentials", description = "Permission: **view_wallets** OR **view_wallet** \n\n Validate Verifiable Credentials", security = { @SecurityRequirement(name = "Authenticate using access_token") }) @RequestBody(content = { - @Content(examples = @ExampleObject(""" + @Content(examples = { @ExampleObject(name = "Validate credential in JSON-LD format", value = """ { "@context": [ "https://www.w3.org/2018/credentials/v1", @@ -976,11 +1041,18 @@ public class IssuersCredentialControllerApiDocs { "verificationMethod": "did:web:localhost:BPNL000000000000#" } } - """)) + """), + @ExampleObject(name = "Validate credential in JWT format", value = """ + { + "jwt": "eyJraWQiOiJkaWQ6d2ViOmFmODgtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMDAjOGYyZWU5ZDItYTM2Yy00MTM4LWJlMWYtYjZmZWZiNmY4MDI0IiwidHlwIjoiSldUIiwiYWxnIjoiRWREU0EifQ.eyJpc3MiOiJkaWQ6d2ViOmFmODgtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMDAiLCJzdWIiOiJkaWQ6d2ViOmFmODgtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMTEiLCJleHAiOjE3MzU2Njk4MDAsInZjIjp7IkBjb250ZXh0IjpbImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL3YxIiwiaHR0cHM6Ly9jb2Zpbml0eS14LmdpdGh1Yi5pby9zY2hlbWEtcmVnaXN0cnkvdjEuMS9Vc2VDYXNlVkMuanNvbiIsImh0dHBzOi8vdzNpZC5vcmcvc2VjdXJpdHkvc3VpdGVzL2p3cy0yMDIwL3YxIl0sImlkIjoiZGlkOndlYjphZjg4LTIwMy0xMjktMjEzLTEwNy5uZ3Jvay1mcmVlLmFwcDpCUE5MMDAwMDAwMDAwMDAwI2Q4Y2ZjZDBiLWY0NGQtNDVkMC05OGEzLTA4ZDZkNmU5Y2E5NSIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVc2VDYXNlRnJhbWV3b3JrQ29uZGl0aW9uIl0sImlzc3VlciI6ImRpZDp3ZWI6YWY4OC0yMDMtMTI5LTIxMy0xMDcubmdyb2stZnJlZS5hcHA6QlBOTDAwMDAwMDAwMDAwMCIsImNyZWRlbnRpYWxTdWJqZWN0IjpbeyJob2xkZXJJZGVudGlmaWVyIjoiQlBOTDAwMDAwMDAwMDAxMSIsImlkIjoiZGlkOndlYjphZjg4LTIwMy0xMjktMjEzLTEwNy5uZ3Jvay1mcmVlLmFwcDpCUE5MMDAwMDAwMDAwMDExIiwidHlwZSI6IkJlaGF2aW9yVHdpbkNyZWRlbnRpYWwiLCJjb250cmFjdFRlbXBsYXRlIjoiaHR0cHM6Ly9wdWJsaWMuY2F0ZW5hLXgub3JnL2NvbnRyYWN0cy90cmFjZWFiaWx0eS52MS5wZGYiLCJjb250cmFjdFZlcnNpb24iOiIxLjAuMCJ9XSwiY3JlZGVudGlhbFN0YXR1cyI6bnVsbCwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wMi0wOFQxNDowMjo1M1oiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMjQtMTItMzFUMTg6MzA6MDBaIn0sImp0aSI6IjliYWFhMjIzLTAxMjctNDEyZS05NjZhLTA3ZTJmZGU4NGNlNCJ9.X3rkj8Gv4OD5nEaeFG5pSA-dogbcYA91YEPmHiKT4FhAiIr7QAdSEULGXHYOn8-eK0jSDHNdAxNYIK1UwYRsCA" + } + """) + } + ) }) public @interface ValidateVerifiableCredentialApiDocs { } - + @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Tag(name = API_TAG_VERIFIABLE_CREDENTIAL_ISSUER) diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/StringPool.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/StringPool.java index 430cf7bae..af0baf346 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/StringPool.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/StringPool.java @@ -102,4 +102,6 @@ private StringPool() { public static final String PRIVATE_KEY = "PRIVATE KEY"; public static final String PUBLIC_KEY = "PUBLIC KEY"; + public static final String VC_JWT_KEY = "jwt"; + } diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/HoldersCredentialController.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/HoldersCredentialController.java index d2d17a20b..ae614c96d 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/HoldersCredentialController.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/HoldersCredentialController.java @@ -29,6 +29,7 @@ import org.eclipse.tractusx.managedidentitywallets.apidocs.HoldersCredentialControllerApiDocs.GetCredentialsApiDocs; import org.eclipse.tractusx.managedidentitywallets.apidocs.HoldersCredentialControllerApiDocs.IssueCredentialApiDoc; import org.eclipse.tractusx.managedidentitywallets.constant.RestURI; +import org.eclipse.tractusx.managedidentitywallets.dto.CredentialsResponse; import org.eclipse.tractusx.managedidentitywallets.service.HoldersCredentialService; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; import org.springframework.data.domain.PageImpl; @@ -101,8 +102,10 @@ public ResponseEntity> getCredentials(@Parameter( @IssueCredentialApiDoc @PostMapping(path = RestURI.CREDENTIALS, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity issueCredential(@RequestBody Map data, Principal principal) { + public ResponseEntity issueCredential(@RequestBody Map data, Principal principal, + @RequestParam(name = "asJwt", defaultValue = "false") boolean asJwt + ) { log.debug("Received request to issue credential. BPN: {}", getBPNFromToken(principal)); - return ResponseEntity.status(HttpStatus.CREATED).body(holdersCredentialService.issueCredential(data, getBPNFromToken(principal))); + return ResponseEntity.status(HttpStatus.CREATED).body(holdersCredentialService.issueCredential(data, getBPNFromToken(principal) , asJwt)); } } diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/IssuersCredentialController.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/IssuersCredentialController.java index 90ff993e3..6cdf43730 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/IssuersCredentialController.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/IssuersCredentialController.java @@ -36,6 +36,8 @@ import org.eclipse.tractusx.managedidentitywallets.apidocs.IssuersCredentialControllerApiDocs.IssueVerifiableCredentialUsingBaseWalletApiDocs; import org.eclipse.tractusx.managedidentitywallets.apidocs.IssuersCredentialControllerApiDocs.ValidateVerifiableCredentialApiDocs; import org.eclipse.tractusx.managedidentitywallets.constant.RestURI; +import org.eclipse.tractusx.managedidentitywallets.dto.CredentialVerificationRequest; +import org.eclipse.tractusx.managedidentitywallets.dto.CredentialsResponse; import org.eclipse.tractusx.managedidentitywallets.dto.IssueDismantlerCredentialRequest; import org.eclipse.tractusx.managedidentitywallets.dto.IssueFrameworkCredentialRequest; import org.eclipse.tractusx.managedidentitywallets.dto.IssueMembershipCredentialRequest; @@ -113,7 +115,7 @@ public ResponseEntity> getCredentials(@Parameter( */ @IssueMembershipCredentialApiDoc @PostMapping(path = RestURI.CREDENTIALS_ISSUER_MEMBERSHIP, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity issueMembershipCredential(@Valid @RequestBody IssueMembershipCredentialRequest issueMembershipCredentialRequest, Principal principal) { + public ResponseEntity issueMembershipCredential(@Valid @RequestBody IssueMembershipCredentialRequest issueMembershipCredentialRequest, Principal principal) { log.debug("Received request to issue membership credential. BPN: {}", getBPNFromToken(principal)); return ResponseEntity.status(HttpStatus.CREATED).body(issuersCredentialService.issueMembershipCredential(issueMembershipCredentialRequest, getBPNFromToken(principal))); } @@ -127,7 +129,7 @@ public ResponseEntity issueMembershipCredential(@Valid @Re */ @IssueDismantlerCredentialApiDoc @PostMapping(path = RestURI.CREDENTIALS_ISSUER_DISMANTLER, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity issueDismantlerCredential(@Valid @RequestBody IssueDismantlerCredentialRequest request, Principal principal) { + public ResponseEntity issueDismantlerCredential(@Valid @RequestBody IssueDismantlerCredentialRequest request, Principal principal) { log.debug("Received request to issue dismantler credential. BPN: {}", getBPNFromToken(principal)); return ResponseEntity.status(HttpStatus.CREATED).body(issuersCredentialService.issueDismantlerCredential(request, getBPNFromToken(principal))); } @@ -141,7 +143,7 @@ public ResponseEntity issueDismantlerCredential(@Valid @Re */ @IssueFrameworkCredentialApiDocs @PostMapping(path = RestURI.API_CREDENTIALS_ISSUER_FRAMEWORK, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity issueFrameworkCredential(@Valid @RequestBody IssueFrameworkCredentialRequest request, Principal principal) { + public ResponseEntity issueFrameworkCredential(@Valid @RequestBody IssueFrameworkCredentialRequest request, Principal principal) { log.debug("Received request to issue framework credential. BPN: {}", getBPNFromToken(principal)); return ResponseEntity.status(HttpStatus.CREATED).body(issuersCredentialService.issueFrameworkCredential(request, getBPNFromToken(principal))); } @@ -155,10 +157,10 @@ public ResponseEntity issueFrameworkCredential(@Valid @Req */ @PostMapping(path = RestURI.CREDENTIALS_VALIDATION, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ValidateVerifiableCredentialApiDocs - public ResponseEntity> credentialsValidation(@RequestBody Map data, + public ResponseEntity> credentialsValidation(@RequestBody CredentialVerificationRequest credentialVerificationRequest, @Parameter(description = "Check expiry of VC") @RequestParam(name = "withCredentialExpiryDate", defaultValue = "false", required = false) boolean withCredentialExpiryDate) { log.debug("Received request to validate verifiable credentials"); - return ResponseEntity.status(HttpStatus.OK).body(issuersCredentialService.credentialsValidation(data, withCredentialExpiryDate)); + return ResponseEntity.status(HttpStatus.OK).body(issuersCredentialService.credentialsValidation(credentialVerificationRequest, withCredentialExpiryDate)); } /** @@ -171,8 +173,10 @@ public ResponseEntity> credentialsValidation(@RequestBody Ma */ @PostMapping(path = RestURI.ISSUERS_CREDENTIALS, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @IssueVerifiableCredentialUsingBaseWalletApiDocs - public ResponseEntity issueCredentialUsingBaseWallet(@Parameter(description = "Holder DID", examples = {@ExampleObject(description = "did", name = "did", value = "did:web:localhost:BPNL000000000000")}) @RequestParam(name = "holderDid") String holderDid, @RequestBody Map data, Principal principal) { + public ResponseEntity issueCredentialUsingBaseWallet(@Parameter(description = "Holder DID", examples = {@ExampleObject(description = "did", name = "did", value = "did:web:localhost:BPNL000000000000")}) @RequestParam(name = "holderDid") String holderDid, + @RequestBody Map data, Principal principal, + @RequestParam(name = "asJwt", defaultValue = "false") boolean asJwt) { log.debug("Received request to issue verifiable credential. BPN: {}", getBPNFromToken(principal)); - return ResponseEntity.status(HttpStatus.CREATED).body(issuersCredentialService.issueCredentialUsingBaseWallet(holderDid, data, getBPNFromToken(principal))); + return ResponseEntity.status(HttpStatus.CREATED).body(issuersCredentialService.issueCredentialUsingBaseWallet(holderDid, data, getBPNFromToken(principal) , asJwt)); } } diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialVerificationRequest.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialVerificationRequest.java new file mode 100644 index 000000000..7e6ba71ab --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialVerificationRequest.java @@ -0,0 +1,40 @@ +/* + * ******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ****************************************************************************** + */ + + package org.eclipse.tractusx.managedidentitywallets.dto; + + import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; + + import java.util.LinkedHashMap; + import java.util.Map; + + public class CredentialVerificationRequest extends LinkedHashMap { + + + public void setJwt(String jwt) { + put(StringPool.VC_JWT_KEY, jwt); + } + + public void setVc(Map vc) { + putAll(vc); + } + } + \ No newline at end of file diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialsResponse.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialsResponse.java new file mode 100644 index 000000000..28041606a --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/CredentialsResponse.java @@ -0,0 +1,39 @@ +/* + * ******************************************************************************* + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ****************************************************************************** + */ + +package org.eclipse.tractusx.managedidentitywallets.dto; + +import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class CredentialsResponse extends LinkedHashMap { + + public void setJwt(String jwt) { + put(StringPool.VC_JWT_KEY, jwt); + } + + public void setVc(Map vc) { + putAll(vc); + } + +} diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueDismantlerCredentialRequest.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueDismantlerCredentialRequest.java index a838d4b6f..677f18cf3 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueDismantlerCredentialRequest.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueDismantlerCredentialRequest.java @@ -1,6 +1,6 @@ /* * ******************************************************************************* - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -27,6 +27,8 @@ import lombok.*; import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.Set; /** @@ -49,4 +51,7 @@ public class IssueDismantlerCredentialRequest { @Builder.Default private Set<@NotBlank String> allowedVehicleBrands = Set.of(); + + @JsonProperty("asJwt") + private boolean asJwt; } diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueFrameworkCredentialRequest.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueFrameworkCredentialRequest.java index 78a13e68a..bf14df523 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueFrameworkCredentialRequest.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueFrameworkCredentialRequest.java @@ -1,6 +1,6 @@ /* * ******************************************************************************* - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -19,36 +19,41 @@ * ****************************************************************************** */ -package org.eclipse.tractusx.managedidentitywallets.dto; - -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; -import lombok.*; - - -/** - * The type Issue framework credential request. - */ -@Getter -@Setter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class IssueFrameworkCredentialRequest { - - @NotBlank(message = "Please provide holder identifier") - @Size(min = 5, max = 255, message = "Please provide valid identifier") - private String holderIdentifier; - - @NotBlank(message = "Please provide type") - private String type; - - @NotBlank(message = "Please provide contract-template") - @JsonProperty("contract-template") - private String contractTemplate; - - @NotBlank(message = "Please provide contract-template") - @JsonProperty("contract-version") - private String contractVersion; -} + package org.eclipse.tractusx.managedidentitywallets.dto; + + import com.fasterxml.jackson.annotation.JsonProperty; + import jakarta.validation.constraints.NotBlank; + import jakarta.validation.constraints.Size; + import lombok.*; + + + /** + * The type Issue framework credential request. + */ + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + @Builder + public class IssueFrameworkCredentialRequest { + + @NotBlank(message = "Please provide holder identifier") + @Size(min = 5, max = 255, message = "Please provide valid identifier") + private String holderIdentifier; + + @NotBlank(message = "Please provide type") + private String type; + + @NotBlank(message = "Please provide contract-template") + @JsonProperty("contract-template") + private String contractTemplate; + + @NotBlank(message = "Please provide contract-template") + @JsonProperty("contract-version") + private String contractVersion; + + @JsonProperty("asJwt") + private boolean asJwt; + + } + \ No newline at end of file diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueMembershipCredentialRequest.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueMembershipCredentialRequest.java index 301a23229..ac9c04f0f 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueMembershipCredentialRequest.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/IssueMembershipCredentialRequest.java @@ -1,6 +1,6 @@ /* * ******************************************************************************* - * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. @@ -19,25 +19,31 @@ * ****************************************************************************** */ -package org.eclipse.tractusx.managedidentitywallets.dto; + package org.eclipse.tractusx.managedidentitywallets.dto; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; -import lombok.*; -import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; - -/** - * The type Issue membership credential request. - */ -@Getter -@Setter -@NoArgsConstructor -@Builder -@AllArgsConstructor -public class IssueMembershipCredentialRequest { - - @NotBlank(message = "Please provide BPN") - @Pattern(regexp = StringPool.BPN_NUMBER_REGEX, message = "Please provide valid BPN") - private String bpn; -} + import jakarta.validation.constraints.NotBlank; + import jakarta.validation.constraints.Pattern; + import lombok.*; + import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; +import com.fasterxml.jackson.annotation.JsonProperty; + + /** + * The type Issue membership credential request. + */ + @Getter + @Setter + @NoArgsConstructor + @Builder + @AllArgsConstructor + public class IssueMembershipCredentialRequest { + + @NotBlank(message = "Please provide BPN") + @Pattern(regexp = StringPool.BPN_NUMBER_REGEX, message = "Please provide valid BPN") + private String bpn; + + @JsonProperty("asJwt") + private boolean asJwt; + } + + \ No newline at end of file diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/HoldersCredentialService.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/HoldersCredentialService.java index 842910245..4fc2935bf 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/HoldersCredentialService.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/HoldersCredentialService.java @@ -36,6 +36,7 @@ import org.eclipse.tractusx.managedidentitywallets.dao.entity.HoldersCredential; import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet; import org.eclipse.tractusx.managedidentitywallets.dao.repository.HoldersCredentialRepository; +import org.eclipse.tractusx.managedidentitywallets.dto.CredentialsResponse; import org.eclipse.tractusx.managedidentitywallets.exception.CredentialNotFoundProblem; import org.eclipse.tractusx.managedidentitywallets.exception.ForbiddenException; import org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils; @@ -143,7 +144,7 @@ public PageImpl getCredentials(String credentialId, String * @param callerBpn the caller bpn * @return the verifiable credential */ - public VerifiableCredential issueCredential(Map data, String callerBpn) { + public CredentialsResponse issueCredential(Map data, String callerBpn , boolean asJwt) { VerifiableCredential verifiableCredential = new VerifiableCredential(data); Wallet issuerWallet = commonService.getWalletByIdentifier(verifiableCredential.getIssuer().toString()); @@ -167,9 +168,18 @@ public VerifiableCredential issueCredential(Map data, String cal //Store Credential in holder table credential = create(credential); - log.debug("VC type of {} issued to bpn ->{}", StringEscapeUtils.escapeJava(verifiableCredential.getTypes().toString()), StringEscapeUtils.escapeJava(callerBpn)); + final CredentialsResponse cr = new CredentialsResponse(); + // Return VC - return credential.getData(); + if (asJwt) { + cr.setJwt(CommonUtils.vcAsJwt(issuerWallet, commonService.getWalletByIdentifier(callerBpn), credential.getData() , walletKeyService)); + } else { + cr.setVc(credential.getData()); + } + + log.debug("VC type of {} issued to bpn ->{}", StringEscapeUtils.escapeJava(verifiableCredential.getTypes().toString()), StringEscapeUtils.escapeJava(callerBpn)); + + return cr; } private void isCredentialExistWithId(String holderDid, String credentialId) { diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IssuersCredentialService.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IssuersCredentialService.java index 012e1e626..0e2522eeb 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IssuersCredentialService.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IssuersCredentialService.java @@ -38,8 +38,10 @@ import org.eclipse.tractusx.managedidentitywallets.dao.entity.HoldersCredential; import org.eclipse.tractusx.managedidentitywallets.dao.entity.IssuersCredential; import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet; +import org.eclipse.tractusx.managedidentitywallets.dao.entity.WalletKey; import org.eclipse.tractusx.managedidentitywallets.dao.repository.HoldersCredentialRepository; import org.eclipse.tractusx.managedidentitywallets.dao.repository.IssuersCredentialRepository; +import org.eclipse.tractusx.managedidentitywallets.dto.CredentialsResponse; import org.eclipse.tractusx.managedidentitywallets.dto.IssueDismantlerCredentialRequest; import org.eclipse.tractusx.managedidentitywallets.dto.IssueFrameworkCredentialRequest; import org.eclipse.tractusx.managedidentitywallets.dto.IssueMembershipCredentialRequest; @@ -48,10 +50,15 @@ import org.eclipse.tractusx.managedidentitywallets.exception.ForbiddenException; import org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils; import org.eclipse.tractusx.managedidentitywallets.utils.Validate; +import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; +import org.eclipse.tractusx.ssi.lib.crypt.x21559.x21559PrivateKey; import org.eclipse.tractusx.ssi.lib.did.resolver.DidResolver; import org.eclipse.tractusx.ssi.lib.did.web.DidWebResolver; import org.eclipse.tractusx.ssi.lib.did.web.util.DidWebParser; +import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtFactory; +import org.eclipse.tractusx.ssi.lib.model.did.Did; import org.eclipse.tractusx.ssi.lib.model.did.DidDocument; +import org.eclipse.tractusx.ssi.lib.model.did.DidParser; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialSubject; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialType; @@ -221,7 +228,7 @@ public VerifiableCredential issueBpnCredential(Wallet baseWallet, Wallet holderW * @return the verifiable credential */ @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED) - public VerifiableCredential issueFrameworkCredential(IssueFrameworkCredentialRequest request, String callerBPN) { + public CredentialsResponse issueFrameworkCredential(IssueFrameworkCredentialRequest request, String callerBPN) { //validate type Validate.isFalse(miwSettings.supportedFrameworkVCTypes().contains(request.getType())).launch(new BadDataException("Framework credential of type " + request.getType() + " is not supported, supported values are " + miwSettings.supportedFrameworkVCTypes())); @@ -257,10 +264,19 @@ public VerifiableCredential issueFrameworkCredential(IssueFrameworkCredentialReq //update summery cred updateSummeryCredentials(baseWallet.getDidDocument(), privateKeyBytes, baseWallet.getDid(), holderWallet.getBpn(), holderWallet.getDid(), request.getType()); - log.debug("Framework VC of type ->{} issued to bpn ->{}", StringEscapeUtils.escapeJava(request.getType()), StringEscapeUtils.escapeJava(holderWallet.getBpn())); + + final CredentialsResponse cr = new CredentialsResponse(); // Return VC - return issuersCredential.getData(); + if (request.isAsJwt()) { + cr.setJwt(CommonUtils.vcAsJwt(baseWallet, holderWallet, issuersCredential.getData() , walletKeyService)); + } else { + cr.setVc(issuersCredential.getData()); + } + + log.debug("Framework VC of type ->{} issued to bpn ->{}", StringEscapeUtils.escapeJava(request.getType()), StringEscapeUtils.escapeJava(holderWallet.getBpn())); + + return cr; } /** @@ -271,7 +287,7 @@ public VerifiableCredential issueFrameworkCredential(IssueFrameworkCredentialReq * @return the verifiable credential */ @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED) - public VerifiableCredential issueDismantlerCredential(IssueDismantlerCredentialRequest request, String callerBPN) { + public CredentialsResponse issueDismantlerCredential(IssueDismantlerCredentialRequest request, String callerBPN) { //Fetch Holder Wallet Wallet holderWallet = commonService.getWalletByIdentifier(request.getBpn()); @@ -307,11 +323,19 @@ public VerifiableCredential issueDismantlerCredential(IssueDismantlerCredentialR //update summery VC updateSummeryCredentials(issuerWallet.getDidDocument(), privateKeyBytes, issuerWallet.getDid(), holderWallet.getBpn(), holderWallet.getDid(), MIWVerifiableCredentialType.DISMANTLER_CREDENTIAL); + + final CredentialsResponse cr = new CredentialsResponse(); + + // Return VC + if (request.isAsJwt()) { + cr.setJwt(CommonUtils.vcAsJwt(issuerWallet, holderWallet, issuersCredential.getData() , walletKeyService)); + } else { + cr.setVc(issuersCredential.getData()); + } log.debug("Dismantler VC issued to bpn -> {}", StringEscapeUtils.escapeJava(request.getBpn())); - // Return VC - return issuersCredential.getData(); + return cr; } /** @@ -322,7 +346,7 @@ public VerifiableCredential issueDismantlerCredential(IssueDismantlerCredentialR * @return the verifiable credential */ @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED) - public VerifiableCredential issueMembershipCredential(IssueMembershipCredentialRequest issueMembershipCredentialRequest, String callerBPN) { + public CredentialsResponse issueMembershipCredential(IssueMembershipCredentialRequest issueMembershipCredentialRequest, String callerBPN) { //Fetch Holder Wallet Wallet holderWallet = commonService.getWalletByIdentifier(issueMembershipCredentialRequest.getBpn()); @@ -362,10 +386,18 @@ public VerifiableCredential issueMembershipCredential(IssueMembershipCredentialR //update summery VC updateSummeryCredentials(issuerWallet.getDidDocument(), privateKeyBytes, issuerWallet.getDid(), holderWallet.getBpn(), holderWallet.getDid(), VerifiableCredentialType.MEMBERSHIP_CREDENTIAL); - log.debug("Membership VC issued to bpn ->{}", StringEscapeUtils.escapeJava(issueMembershipCredentialRequest.getBpn())); + final CredentialsResponse cr = new CredentialsResponse(); // Return VC - return issuersCredential.getData(); + if (issueMembershipCredentialRequest.isAsJwt()) { + cr.setJwt(CommonUtils.vcAsJwt(issuerWallet, holderWallet, issuersCredential.getData() , walletKeyService)); + } else { + cr.setVc(issuersCredential.getData()); + } + + log.debug("Membership VC issued to bpn ->{}", StringEscapeUtils.escapeJava(issueMembershipCredentialRequest.getBpn())); + + return cr; } @@ -378,7 +410,7 @@ public VerifiableCredential issueMembershipCredential(IssueMembershipCredentialR * @return the verifiable credential */ @Transactional(isolation = Isolation.READ_UNCOMMITTED, propagation = Propagation.REQUIRED) - public VerifiableCredential issueCredentialUsingBaseWallet(String holderDid, Map data, String callerBpn) { + public CredentialsResponse issueCredentialUsingBaseWallet(String holderDid, Map data, String callerBpn , boolean asJwt) { //Fetch Holder Wallet Wallet holderWallet = commonService.getWalletByIdentifier(holderDid); @@ -411,10 +443,18 @@ public VerifiableCredential issueCredentialUsingBaseWallet(String holderDid, Map IssuersCredential issuersCredential = IssuersCredential.of(holdersCredential); issuersCredential = create(issuersCredential); - log.debug("VC type of {} issued to bpn ->{}", StringEscapeUtils.escapeJava(verifiableCredential.getTypes().toString()), StringEscapeUtils.escapeJava(holderWallet.getBpn())); + final CredentialsResponse cr = new CredentialsResponse(); // Return VC - return issuersCredential.getData(); + if (asJwt) { + cr.setJwt(CommonUtils.vcAsJwt(issuerWallet, holderWallet, issuersCredential.getData() , walletKeyService)); + } else { + cr.setVc(issuersCredential.getData()); + } + + log.debug("VC type of {} issued to bpn ->{}", StringEscapeUtils.escapeJava(verifiableCredential.getTypes().toString()), StringEscapeUtils.escapeJava(holderWallet.getBpn())); + + return cr; } /** diff --git a/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java b/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java index 338311669..92df72399 100644 --- a/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java +++ b/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java @@ -29,11 +29,15 @@ import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; import org.eclipse.tractusx.managedidentitywallets.dao.entity.HoldersCredential; import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest; +import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet; +import org.eclipse.tractusx.managedidentitywallets.dao.entity.WalletKey; import org.eclipse.tractusx.managedidentitywallets.exception.BadDataException; -import org.eclipse.tractusx.ssi.lib.crypt.x21559.x21559PrivateKey; -import org.eclipse.tractusx.ssi.lib.exception.InvalidePrivateKeyFormat; -import org.eclipse.tractusx.ssi.lib.exception.UnsupportedSignatureTypeException; +import org.eclipse.tractusx.managedidentitywallets.service.WalletKeyService; +import org.eclipse.tractusx.ssi.lib.crypt.octet.OctetKeyPairFactory; +import org.eclipse.tractusx.ssi.lib.jwt.SignedJwtFactory; +import org.eclipse.tractusx.ssi.lib.model.did.Did; import org.eclipse.tractusx.ssi.lib.model.did.DidDocument; +import org.eclipse.tractusx.ssi.lib.model.did.DidParser; import org.eclipse.tractusx.ssi.lib.model.proof.jws.JWSSignature2020; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredential; import org.eclipse.tractusx.ssi.lib.model.verifiable.credential.VerifiableCredentialBuilder; @@ -44,6 +48,8 @@ import org.springframework.util.MultiValueMap; import java.io.StringWriter; +import com.nimbusds.jwt.SignedJWT; + import java.net.URI; import java.time.Instant; import java.util.ArrayList; @@ -61,7 +67,6 @@ public class CommonUtils { public static final Pattern BPN_NUMBER_PATTERN = Pattern.compile(StringPool.BPN_NUMBER_REGEX); - /** * Gets identifier type. * @@ -72,12 +77,12 @@ public static String getIdentifierType(String identifier) { if (identifier.startsWith("did:web")) { return StringPool.DID; } else { - Validate.isFalse(BPN_NUMBER_PATTERN.matcher(identifier).matches()).launch(new BadDataException("Invalid BPN number - " + identifier)); + Validate.isFalse(BPN_NUMBER_PATTERN.matcher(identifier).matches()) + .launch(new BadDataException("Invalid BPN number - " + identifier)); return StringPool.BPN; } } - /** * Gets credential. * @@ -88,8 +93,9 @@ public static String getIdentifierType(String identifier) { * @param holderDid the holder did * @return the credential */ - public static HoldersCredential getHoldersCredential(VerifiableCredentialSubject subject, List types, DidDocument issuerDoc, - byte[] privateKeyBytes, String holderDid, List contexts, Date expiryDate, boolean selfIssued) { + public static HoldersCredential getHoldersCredential(VerifiableCredentialSubject subject, List types, + DidDocument issuerDoc, + byte[] privateKeyBytes, String holderDid, List contexts, Date expiryDate, boolean selfIssued) { List cloneTypes = new ArrayList<>(types); // Create VC @@ -122,7 +128,8 @@ private static VerifiableCredential createVerifiableCredential(DidDocument issue } // check if the expiryDate is set - // if its null then it will be ignored from the SSI Lib (VerifiableCredentialBuilder) and will not be added to the VC + // if its null then it will be ignored from the SSI Lib + // (VerifiableCredentialBuilder) and will not be added to the VC Instant expiryInstant = null; if (expiryDate != null) { expiryInstant = expiryDate.toInstant(); @@ -138,18 +145,16 @@ private static VerifiableCredential createVerifiableCredential(DidDocument issue .issuanceDate(Instant.now()) .credentialSubject(verifiableCredentialSubject); - LinkedDataProofGenerator generator = LinkedDataProofGenerator.newInstance(SignatureType.JWS); URI verificationMethod = issuerDoc.getVerificationMethods().get(0).getId(); - JWSSignature2020 proof = - (JWSSignature2020) generator.createProof(builder.build(), verificationMethod, new x21559PrivateKey(privateKey)); + JWSSignature2020 proof = (JWSSignature2020) generator.createProof(builder.build(), verificationMethod, + new x21559PrivateKey(privateKey)); - - //Adding Proof to VC + // Adding Proof to VC builder.proof(proof); - //Create Credential + // Create Credential return builder.build(); } @@ -168,4 +173,25 @@ public static SecureTokenRequest getSecureTokenRequest(MultiValueMap singleValueMap = map.toSingleValueMap(); return objectMapper.convertValue(singleValueMap, SecureTokenRequest.class); } + + public static String vcAsJwt(Wallet issuerWallet, Wallet holderWallet, VerifiableCredential vc , WalletKeyService walletKeyService) { + + Did issuerDid = DidParser.parse(issuerWallet.getDid()); + Did holderDid = DidParser.parse(holderWallet.getDid()); + + WalletKey walletKey = walletKeyService.get(issuerWallet.getId()); + + // JWT Factory + SerializedJwtVCFactoryImpl vcFactory = new SerializedJwtVCFactoryImpl( + new SignedJwtFactory(new OctetKeyPairFactory())); + + x21559PrivateKey privateKey = walletKeyService.getPrivateKeyByWalletIdentifier(walletKey.getId()); + // JWT Factory + + SignedJWT vcJWT = vcFactory.createVCJwt(issuerDid, holderDid, Date.from(vc.getExpirationDate()), vc, + privateKey, + walletKey.getKeyId()); + + return vcJWT.serialize(); + } }