From c19c1b6b1fcd10d3867d7955a7f7b4f246d70051 Mon Sep 17 00:00:00 2001 From: Dominik Pinsel Date: Tue, 9 Jul 2024 14:11:23 +0200 Subject: [PATCH] feat(identity-trust): update protocol Signed-off-by: Dominik Pinsel --- .../config/security/SecurityConfig.java | 9 +- .../constant/RestURI.java | 2 + .../controller/PresentationController.java | 37 +++- .../controller/SecureTokenController.java | 132 ++++++++----- .../domain/StsTokenResponse.java | 4 +- .../dto/PresentationResponseMessage.java | 58 ++++++ .../dto/SecureTokenRequest.java | 69 +++---- .../dto/SecureTokenRequestScope.java | 45 +++++ .../dto/SecureTokenRequestToken.java | 39 ++++ .../reader/TractusXJsonLdReader.java | 75 ++++++++ .../TractusXPresentationRequestReader.java | 85 +++++++++ .../service/IdpAuthorization.java | 86 --------- .../service/PresentationService.java | 1 + .../service/STSTokenValidationService.java | 4 + .../utils/CommonUtils.java | 7 - .../utils/ResourceUtil.java | 61 ++++++ .../SecureTokenRequestValidator.java | 70 ------- .../resources/jsonld/IdentityMinusTrust.json | 127 ++++++++++++ .../config/TestContextInitializer.java | 2 +- .../controller/SecureTokenControllerTest.java | 45 ++--- ...PresentationResponseSerializationTest.java | 112 +++++++++++ .../identityminustrust/TokenRequestTest.java | 180 ++++++++++++++++++ .../messages/presentation_query.json | 10 + .../messages/token_request_with_scope.json | 10 + .../messages/token_request_with_token.json | 8 + .../reader/PresentationRequestReaderTest.java | 49 +++++ .../vp/PresentationServiceTest.java | 3 - .../messages/presentation_query.json | 10 + .../messages/token_request_with_scope.json | 10 + .../messages/token_request_with_token.json | 8 + 30 files changed, 1048 insertions(+), 310 deletions(-) create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseMessage.java create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestScope.java create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestToken.java create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXJsonLdReader.java create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXPresentationRequestReader.java delete mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IdpAuthorization.java create mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/ResourceUtil.java delete mode 100644 miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/validator/SecureTokenRequestValidator.java create mode 100644 miw/src/main/resources/jsonld/IdentityMinusTrust.json create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseSerializationTest.java create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/TokenRequestTest.java create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/presentation_query.json create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_scope.json create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_token.json create mode 100644 miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/reader/PresentationRequestReaderTest.java create mode 100644 miw/src/test/resources/identityminustrust/messages/presentation_query.json create mode 100644 miw/src/test/resources/identityminustrust/messages/token_request_with_scope.json create mode 100644 miw/src/test/resources/identityminustrust/messages/token_request_with_token.json diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/config/security/SecurityConfig.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/config/security/SecurityConfig.java index 59bce9fad..aa50b525a 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/config/security/SecurityConfig.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/config/security/SecurityConfig.java @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.managedidentitywallets.constant.ApplicationRole; import org.eclipse.tractusx.managedidentitywallets.constant.RestURI; +import org.eclipse.tractusx.managedidentitywallets.controller.SecureTokenController; import org.eclipse.tractusx.managedidentitywallets.service.STSTokenValidationService; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.ApplicationEventPublisher; @@ -80,10 +81,12 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers(new AntPathRequestMatcher("/docs/api-docs/**")).permitAll() .requestMatchers(new AntPathRequestMatcher("/ui/swagger-ui/**")).permitAll() .requestMatchers(new AntPathRequestMatcher("/actuator/health/**")).permitAll() - .requestMatchers(new AntPathRequestMatcher("/api/token", POST.name())).permitAll() - .requestMatchers(new AntPathRequestMatcher("/api/presentations/iatp", GET.name())).permitAll() + .requestMatchers(new AntPathRequestMatcher(RestURI.API_PRESENTATIONS_IATP, POST.name())).permitAll() .requestMatchers(new AntPathRequestMatcher("/actuator/loggers/**")).hasRole(ApplicationRole.ROLE_MANAGE_APP) + // secure token request + .requestMatchers(new AntPathRequestMatcher(SecureTokenController.BASE_PATH, POST.name())).hasAnyRole(ApplicationRole.ROLE_VIEW_WALLET) + //did document resolve APIs .requestMatchers(new AntPathRequestMatcher(RestURI.DID_RESOLVE, GET.name())).permitAll() //Get did document .requestMatchers(new AntPathRequestMatcher(RestURI.DID_DOCUMENTS, GET.name())).permitAll() //Get did document @@ -137,7 +140,7 @@ public WebSecurityCustomizer securityCustomizer() { */ @Bean public AuthenticationEventPublisher authenticationEventPublisher - (ApplicationEventPublisher applicationEventPublisher) { + (ApplicationEventPublisher applicationEventPublisher) { return new DefaultAuthenticationEventPublisher(applicationEventPublisher); } } diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/RestURI.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/RestURI.java index 764a0af4d..103f65862 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/RestURI.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/constant/RestURI.java @@ -71,10 +71,12 @@ private RestURI() { * The constant API_PRESENTATIONS. */ public static final String API_PRESENTATIONS = "/api/presentations"; + /** * The constant API_PRESENTATIONS_VALIDATION. */ public static final String API_PRESENTATIONS_VALIDATION = "/api/presentations/validation"; + /** * The constant API_PRESENTATIONS_IATP. */ diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/PresentationController.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/PresentationController.java index 1a2f7d878..a228b21f7 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/PresentationController.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/PresentationController.java @@ -24,23 +24,28 @@ import com.nimbusds.jwt.SignedJWT; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.managedidentitywallets.apidocs.PresentationControllerApiDocs.GetVerifiablePresentationIATPApiDocs; import org.eclipse.tractusx.managedidentitywallets.apidocs.PresentationControllerApiDocs.PostVerifiablePresentationApiDocs; import org.eclipse.tractusx.managedidentitywallets.apidocs.PresentationControllerApiDocs.PostVerifiablePresentationValidationApiDocs; import org.eclipse.tractusx.managedidentitywallets.constant.RestURI; +import org.eclipse.tractusx.managedidentitywallets.dto.PresentationResponseMessage; +import org.eclipse.tractusx.managedidentitywallets.reader.TractusXPresentationRequestReader; import org.eclipse.tractusx.managedidentitywallets.service.PresentationService; +import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentation; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.io.InputStream; import java.security.Principal; +import java.util.List; import java.util.Map; import static org.eclipse.tractusx.managedidentitywallets.utils.TokenParsingUtils.getAccessToken; @@ -55,6 +60,8 @@ public class PresentationController extends BaseController { private final PresentationService presentationService; + private final TractusXPresentationRequestReader presentationRequestReader; + /** * Create presentation response entity. * @@ -97,17 +104,29 @@ public ResponseEntity> validatePresentation(@RequestBody Map /** * Create presentation response entity for VC types provided in STS token. * - * @param stsToken the STS token with required scopes - * @param asJwt as JWT VP response + * @param stsToken the STS token with required scopes + * @param asJwt as JWT VP response * @return the VP response entity */ - @GetMapping(path = RestURI.API_PRESENTATIONS_IATP, produces = { MediaType.APPLICATION_JSON_VALUE }) + @PostMapping(path = RestURI.API_PRESENTATIONS_IATP, produces = { MediaType.APPLICATION_JSON_VALUE }) @GetVerifiablePresentationIATPApiDocs - public ResponseEntity> createPresentation(@Parameter(hidden = true) @RequestHeader(name = "Authorization") String stsToken, - @RequestParam(name = "asJwt", required = false, defaultValue = "false") boolean asJwt) { - SignedJWT accessToken = getAccessToken(stsToken); - Map vp = presentationService.createVpWithRequiredScopes(accessToken, asJwt); - return ResponseEntity.ok(vp); + @SneakyThrows + public ResponseEntity createPresentation(@Parameter(hidden = true) @RequestHeader(name = "Authorization") String stsToken, + @RequestParam(name = "asJwt", required = false, defaultValue = "false") boolean asJwt, + InputStream is) { + try { + + final List requestedScopes = presentationRequestReader.readVerifiableCredentialScopes(is); + // requested scopes are ignored until the documentation is better refined + + SignedJWT accessToken = getAccessToken(stsToken); + Map map = presentationService.createVpWithRequiredScopes(accessToken, asJwt); + VerifiablePresentation verifiablePresentation = new VerifiablePresentation(map); + PresentationResponseMessage message = new PresentationResponseMessage(verifiablePresentation); + return ResponseEntity.ok(message); + } catch (TractusXPresentationRequestReader.InvalidPresentationQueryMessageResource e) { + return ResponseEntity.badRequest().build(); + } } } diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenController.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenController.java index 3cfd78657..7788c07ca 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenController.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenController.java @@ -21,94 +21,90 @@ package org.eclipse.tractusx.managedidentitywallets.controller; +import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.JWTParser; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.coyote.BadRequestException; import org.eclipse.tractusx.managedidentitywallets.apidocs.SecureTokenControllerApiDoc; import org.eclipse.tractusx.managedidentitywallets.constant.StringPool; import org.eclipse.tractusx.managedidentitywallets.dao.entity.Wallet; import org.eclipse.tractusx.managedidentitywallets.dao.repository.WalletRepository; -import org.eclipse.tractusx.managedidentitywallets.domain.BusinessPartnerNumber; import org.eclipse.tractusx.managedidentitywallets.domain.DID; -import org.eclipse.tractusx.managedidentitywallets.domain.IdpTokenResponse; import org.eclipse.tractusx.managedidentitywallets.domain.SigningServiceType; import org.eclipse.tractusx.managedidentitywallets.domain.StsTokenErrorResponse; import org.eclipse.tractusx.managedidentitywallets.domain.StsTokenResponse; import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest; +import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequestScope; +import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequestToken; import org.eclipse.tractusx.managedidentitywallets.exception.InvalidIdpTokenResponseException; import org.eclipse.tractusx.managedidentitywallets.exception.InvalidSecureTokenRequestException; import org.eclipse.tractusx.managedidentitywallets.exception.UnknownBusinessPartnerNumberException; import org.eclipse.tractusx.managedidentitywallets.exception.UnsupportedGrantTypeException; -import org.eclipse.tractusx.managedidentitywallets.service.IdpAuthorization; import org.eclipse.tractusx.managedidentitywallets.signing.SigningService; -import org.eclipse.tractusx.managedidentitywallets.validator.SecureTokenRequestValidator; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import java.security.Principal; import java.text.ParseException; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; - -import static org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils.getSecureTokenRequest; - +import java.util.stream.Collectors; @RestController @Slf4j @RequiredArgsConstructor @Tag(name = "STS") -public class SecureTokenController { +public class SecureTokenController extends BaseController { + public static final String BASE_PATH = "/api/token"; - private final IdpAuthorization idpAuthorization; private final WalletRepository walletRepo; private final Map availableSigningServices; - @InitBinder - void initBinder(WebDataBinder webDataBinder) { - webDataBinder.addValidators(new SecureTokenRequestValidator()); - } - - @SneakyThrows - @PostMapping(path = "/api/token", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE }) + @PostMapping(path = BASE_PATH, consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE }) @SecureTokenControllerApiDoc.PostSecureTokenDocJson public ResponseEntity tokenJson( - @Valid @RequestBody SecureTokenRequest secureTokenRequest + @RequestBody String data, + Principal principal ) { - return processTokenRequest(secureTokenRequest); + var request = new ObjectMapper().readValue(data, SecureTokenRequest.class); + return processRequest(request, principal); } - @SneakyThrows - @PostMapping(path = "/api/token", consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE }) - @SecureTokenControllerApiDoc.PostSecureTokenDocFormUrlencoded - public ResponseEntity tokenFormUrlencoded( - @Valid @RequestBody MultiValueMap requestParameters - ) { - final SecureTokenRequest secureTokenRequest = getSecureTokenRequest(requestParameters); - return processTokenRequest(secureTokenRequest); + private ResponseEntity processRequest(SecureTokenRequest secureTokenRequest, + Principal principal) throws ParseException, BadRequestException { + + var bpn = getBPNFromToken(principal); + + /* If Token is Present */ + if (secureTokenRequest.getSecureTokenRequestToken().isPresent()) { + return processWithToken(secureTokenRequest.getSecureTokenRequestToken().get(), bpn); + /* Else If Scope is Present */ + } else if (secureTokenRequest.getSecureTokenRequestScope().isPresent()) { + return processWithScope(secureTokenRequest.getSecureTokenRequestScope().get(), bpn); + /* Else Throw */ + } else { + throw new BadRequestException("The provided data could not be used to create and sign a token."); + } } - private ResponseEntity processTokenRequest(SecureTokenRequest secureTokenRequest) throws ParseException { - // handle idp authorization - IdpTokenResponse idpResponse = idpAuthorization.fromSecureTokenRequest(secureTokenRequest); - BusinessPartnerNumber bpn = idpResponse.bpn(); - Wallet selfWallet = walletRepo.getByBpn(bpn.toString()); + + private ResponseEntity processWithToken(SecureTokenRequestToken secureTokenRequest, String bpn) throws ParseException { + Wallet selfWallet = walletRepo.getByBpn(bpn); DID selfDid = new DID(selfWallet.getDid()); DID partnerDid; if (Pattern.compile(StringPool.BPN_NUMBER_REGEX).matcher(secureTokenRequest.getAudience()).matches()) { @@ -124,29 +120,63 @@ private ResponseEntity processTokenRequest(SecureTokenRequest // create the SI token and put/create the access_token inside JWT responseJwt; - if (secureTokenRequest.assertValidWithAccessToken()) { - log.debug("Signing si token."); - responseJwt = signingService.issueToken( - selfDid, - partnerDid, - JWTParser.parse(secureTokenRequest.getAccessToken()) - ); - } else if (secureTokenRequest.assertValidWithScopes()) { - log.debug("Creating access token and signing si token."); - responseJwt = signingService.issueToken( - selfDid, - partnerDid, - Set.of(secureTokenRequest.getBearerAccessScope()) - ); + log.debug("Signing si token."); + responseJwt = signingService.issueToken( + selfDid, + partnerDid, + JWTParser.parse(secureTokenRequest.getToken()) + ); + + // create the response + log.debug("Preparing StsTokenResponse."); + StsTokenResponse response = StsTokenResponse.builder() + .token(responseJwt.serialize()) + .build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + private ResponseEntity processWithScope(SecureTokenRequestScope secureTokenRequest, String bpn) { + Wallet selfWallet = walletRepo.getByBpn(bpn); + DID selfDid = new DID(selfWallet.getDid()); + DID partnerDid; + if (Pattern.compile(StringPool.BPN_NUMBER_REGEX).matcher(secureTokenRequest.getConsumerDid()).matches()) { + partnerDid = new DID(walletRepo.getByBpn(secureTokenRequest.getConsumerDid()).getDid()); + } else if (StringUtils.startsWith(secureTokenRequest.getConsumerDid(), "did:")) { + partnerDid = new DID(secureTokenRequest.getConsumerDid()); } else { - throw new InvalidSecureTokenRequestException("The provided data could not be used to create and sign a token."); + throw new InvalidSecureTokenRequestException("You must provide an audience either as a BPN or DID."); } + SigningServiceType signingServiceType = selfWallet.getSigningServiceType(); + SigningService signingService = availableSigningServices.get(signingServiceType); + + // create the SI token and put/create the access_token inside + JWT responseJwt; + log.debug("Creating access token and signing si token."); + + var scope = secureTokenRequest.getScope(); + if (!scope.equalsIgnoreCase("read")) { + throw new UnsupportedOperationException("Only read scope is supported."); + } + + var scopes = secureTokenRequest.getCredentialTypes() + .stream() + // Why this strange scopes? Doesn't make sense, but done as defined here + // https://github.com/eclipse-tractusx/identity-trust/blob/main/specifications/verifiable.presentation.protocol.md#3-security + .map("hereCouldBeYourText:%s:read"::formatted) + .collect(Collectors.toSet()); + + responseJwt = signingService.issueToken( + selfDid, + partnerDid, + scopes + ); + // create the response log.debug("Preparing StsTokenResponse."); StsTokenResponse response = StsTokenResponse.builder() .token(responseJwt.serialize()) - .expiresAt(responseJwt.getJWTClaimsSet().getExpirationTime().getTime()) .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/domain/StsTokenResponse.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/domain/StsTokenResponse.java index 50161b118..4444f1a75 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/domain/StsTokenResponse.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/domain/StsTokenResponse.java @@ -35,8 +35,6 @@ @AllArgsConstructor public class StsTokenResponse { - @JsonProperty("access_token") + @JsonProperty("jwt") private String token; - - private long expiresAt; } diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseMessage.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseMessage.java new file mode 100644 index 000000000..8fc9e8858 --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseMessage.java @@ -0,0 +1,58 @@ +/* + * ******************************************************************************* + * 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 com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentation; + +import java.util.List; + +/** + * Class to represent the response message of a presentation request. + * Defined in JsonLD Tractus-X context.json. + *

+ * As `presentationSubmission` a not well-defined, so we will just skip them. Defining all types as 'Json' make the whole idea of using Json-Linked-Data a waste of time, but ok. + *

+ * The `presentation` property is also specified as 'Json'. As we are now allowed to skip them we will assume these are Presentations from ether the Verifiable Credential Data Model v1.1 or Verifiable Credential Data Model v2.0. ( It would be so convenient, if there would be a way do differentiate these different types of data! ) + */ +@Getter +public class PresentationResponseMessage { + + + public PresentationResponseMessage(VerifiablePresentation verifiablePresentation) { + this(List.of(verifiablePresentation)); + } + + public PresentationResponseMessage(List verifiablePresentations) { + this.verifiablePresentations = verifiablePresentations; + } + + @JsonProperty("@context") + private List contexts = List.of("https://w3id.org/tractusx-trust/v0.8"); + + @JsonProperty("@type") + private List types = List.of("PresentationResponseMessage"); + + @JsonProperty("presentation") + private List verifiablePresentations; +} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequest.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequest.java index 5eb7c931d..13f3cf814 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequest.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequest.java @@ -21,55 +21,36 @@ package org.eclipse.tractusx.managedidentitywallets.dto; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.Data; +import lombok.ToString; -@NoArgsConstructor -@AllArgsConstructor -@Builder -@Getter -@Setter +@Data +@ToString public class SecureTokenRequest { - private String audience; - - @JsonProperty("client_id") - private String clientId; - - @JsonProperty("client_secret") - private String clientSecret; - - @JsonProperty("grant_type") - private String grantType; - - @JsonProperty("access_token") - private String accessToken; - - @JsonProperty("bearer_access_alias") - private String bearerAccessAlias; - - @JsonProperty("bearer_access_scope") - private String bearerAccessScope; - - public boolean assertValidWithScopes() { - return bearerAccessScope != null && accessToken == null && !bearerAccessScope.isEmpty(); - } - public boolean assertValidWithAccessToken() { - return accessToken != null && bearerAccessScope == null; + /** + * SecureTokenRequestScope request scope, may be null if token is present + */ + @JsonProperty("grantAccess") + private SecureTokenRequestScope grantAccess; + + /** + * SecureTokenRequestToken request token, may be null if scope is present + */ + @JsonProperty("signToken") + private SecureTokenRequestToken signToken; + + @JsonIgnore + public Optional getSecureTokenRequestScope() { + return Optional.ofNullable(grantAccess); } - @Override - public String toString() { - return "SecureTokenRequest{" + - "audience='" + audience + '\'' + - ", clientId='" + clientId + '\'' + - ", grantType='" + grantType + '\'' + - ", bearerAccessAlias='" + bearerAccessAlias + '\'' + - ", bearerAccessScope='" + bearerAccessScope + '\'' + - '}'; + @JsonIgnore + public Optional getSecureTokenRequestToken() { + return Optional.ofNullable(signToken); } } diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestScope.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestScope.java new file mode 100644 index 000000000..59080f73a --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestScope.java @@ -0,0 +1,45 @@ +/* + * ******************************************************************************* + * 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 com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.ToString; + +import java.util.List; + +@Data +@ToString +public class SecureTokenRequestScope { + + @JsonProperty("scope") + private String scope; + + @JsonProperty("credentialTypes") + private List credentialTypes; + + @JsonProperty("consumerDid") + private String consumerDid; + + @JsonProperty("providerDid") + private String providerDid; +} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestToken.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestToken.java new file mode 100644 index 000000000..fb1b69e68 --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/dto/SecureTokenRequestToken.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 lombok.Data; +import lombok.ToString; + +@Data +@ToString +public class SecureTokenRequestToken { + + @ToString.Exclude + private String token; + + private String issuer; + + private String audience; + + private String subject; +} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXJsonLdReader.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXJsonLdReader.java new file mode 100644 index 000000000..8a15904fc --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXJsonLdReader.java @@ -0,0 +1,75 @@ +/* + * ******************************************************************************* + * 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.reader; + +import com.apicatalog.jsonld.JsonLdError; +import com.apicatalog.jsonld.JsonLdOptions; +import com.apicatalog.jsonld.document.JsonDocument; +import com.apicatalog.jsonld.processor.ExpansionProcessor; +import jakarta.json.JsonArray; +import lombok.NonNull; +import org.eclipse.tractusx.managedidentitywallets.utils.ResourceUtil; +import org.eclipse.tractusx.ssi.lib.model.RemoteDocumentLoader; + +import java.io.InputStream; +import java.net.URI; +import java.util.Map; + +public class TractusXJsonLdReader { + + private static final String TRACTUS_X_CONTEXT_RESOURCE = "jsonld/IdentityMinusTrust.json"; + private static final URI TRACTUS_X_CONTEXT = URI.create("https://w3id.org/tractusx-trust/v0.8"); + + private final RemoteDocumentLoader documentLoader = RemoteDocumentLoader.DOCUMENT_LOADER; + + public TractusXJsonLdReader() { + + documentLoader.setEnableHttps(true); // HTTPS context loading is required + + final boolean isOfflineContextCached = documentLoader.getLocalCache().containsKey(TRACTUS_X_CONTEXT); + if (!isOfflineContextCached) { + loadOfflineContext(); + } + } + + public JsonArray expand(@NonNull final InputStream documentStream) throws JsonLdError { + + final JsonLdOptions jsonLdOptions = new JsonLdOptions(); + jsonLdOptions.setDocumentLoader(documentLoader); + + final JsonDocument document = JsonDocument.of(com.apicatalog.jsonld.http.media.MediaType.JSON_LD, documentStream); + return ExpansionProcessor.expand(document, jsonLdOptions, false); + } + + private void loadOfflineContext() { + try { + final InputStream context = ResourceUtil.getResourceStream(TRACTUS_X_CONTEXT_RESOURCE); + final JsonDocument identityMinusTrustDocument; + identityMinusTrustDocument = JsonDocument.of(com.apicatalog.jsonld.http.media.MediaType.JSON_LD, context); + documentLoader.setEnableLocalCache(true); + documentLoader.setLocalCache(Map.of(TRACTUS_X_CONTEXT, identityMinusTrustDocument)); + } catch (JsonLdError e) { + // If this ever fails, it is a programming error. Loading of the embedded context resource is checked by Unit Tests. + throw new RuntimeException("Could not parse Tractus-X JsonL-d context from resource. This should never happen. Resource: '%s'".formatted(TRACTUS_X_CONTEXT_RESOURCE), e); + } + } +} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXPresentationRequestReader.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXPresentationRequestReader.java new file mode 100644 index 000000000..502bdeb3b --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/reader/TractusXPresentationRequestReader.java @@ -0,0 +1,85 @@ +/* + * ******************************************************************************* + * 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.reader; + +import com.apicatalog.jsonld.JsonLdError; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.io.InputStream; +import java.util.List; + +@Slf4j +@Component +public class TractusXPresentationRequestReader extends TractusXJsonLdReader { + + private static final String JSON_LD_TYPE = "@type"; + private static final String JSON_LD_VALUE = "@value"; + private static final String TRACTUS_X_PRESENTATION_QUERY_MESSAGE_TYPE = "https://w3id.org/tractusx-trust/v0.8/PresentationQueryMessage"; + private static final String TRACTUS_X_SCOPE_TYPE = "https://w3id.org/tractusx-trust/v0.8/scope"; + + public List readVerifiableCredentialScopes(InputStream is) throws InvalidPresentationQueryMessageResource { + try { + + final JsonArray jsonArray = expand(is); + + if (jsonArray.size() != 1) { + log.atDebug().addArgument(jsonArray::toString).log("Expanded JSON-LD: {}"); + throw new InvalidPresentationQueryMessageResource("Expected a single JSON object. Found %d".formatted(jsonArray.size())); + } + + var jsonObject = jsonArray.getJsonObject(0); + + final JsonArray typeArray = jsonObject.getJsonArray(JSON_LD_TYPE); + final List types = typeArray.getValuesAs(JsonString.class).stream().map(JsonString::getString).toList(); + if (!types.contains(TRACTUS_X_PRESENTATION_QUERY_MESSAGE_TYPE)) { + log.atDebug().addArgument(jsonArray::toString).log("Expanded JSON-LD: {}"); + throw new InvalidPresentationQueryMessageResource("Unexpected type. Expected %s".formatted(TRACTUS_X_PRESENTATION_QUERY_MESSAGE_TYPE)); + } + + final JsonArray scopes = jsonObject.getJsonArray(TRACTUS_X_SCOPE_TYPE); + return scopes.getValuesAs(JsonObject.class) + .stream() + .map(o -> o.getJsonString(JSON_LD_VALUE)) + .map(JsonString::getString) + .toList(); + + } catch (JsonLdError e) { + throw new InvalidPresentationQueryMessageResource(e); + } + } + + public static class InvalidPresentationQueryMessageResource extends Exception { + public InvalidPresentationQueryMessageResource(String message) { + super(message); + } + + public InvalidPresentationQueryMessageResource(Throwable cause) { + super(cause); + } + } + +} + diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IdpAuthorization.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IdpAuthorization.java deleted file mode 100644 index 956a938cb..000000000 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/IdpAuthorization.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ******************************************************************************* - * 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.service; - -import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.managedidentitywallets.config.security.SecurityConfigProperties; -import org.eclipse.tractusx.managedidentitywallets.domain.IdpTokenResponse; -import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest; -import org.eclipse.tractusx.managedidentitywallets.exception.UnsupportedGrantTypeException; -import org.eclipse.tractusx.managedidentitywallets.exception.InvalidIdpTokenResponseException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -import static org.eclipse.tractusx.managedidentitywallets.constant.StringPool.CLIENT_CREDENTIALS; -import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.CLIENT_ID; -import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.CLIENT_SECRET; -import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.GRANT_TYPE; -import static org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames.SCOPE; -import static org.springframework.security.oauth2.core.oidc.OidcScopes.OPENID; - -@Service -@Slf4j -public class IdpAuthorization { - - private final RestTemplate rest; - - @Autowired - public IdpAuthorization(final SecurityConfigProperties properties, final RestTemplateBuilder restTemplateBuilder) { - String url = UriComponentsBuilder.fromUriString(properties.authServerUrl()) - .pathSegment("realms", properties.realm()) - .build() - .toString(); - this.rest = restTemplateBuilder - .rootUri(url) - .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE) - .build(); - } - - public IdpTokenResponse fromSecureTokenRequest(SecureTokenRequest secureTokenRequest) throws UnsupportedGrantTypeException, InvalidIdpTokenResponseException { - // we're ignoring the input, but the protocol requires us to check. - if (!secureTokenRequest.getGrantType().equals(CLIENT_CREDENTIALS)) { - throw new UnsupportedGrantTypeException("The provided 'grant_type' is not valid. Use 'client_credentials'."); - } - MultiValueMap tokenRequest = new LinkedMultiValueMap<>(); - tokenRequest.add(GRANT_TYPE, CLIENT_CREDENTIALS); - tokenRequest.add(SCOPE, OPENID); - tokenRequest.add(CLIENT_ID, secureTokenRequest.getClientId()); - tokenRequest.add(CLIENT_SECRET, secureTokenRequest.getClientSecret()); - log.debug("Doing OAuth token request for '{}' during secure token request flow.", secureTokenRequest.getClientId()); - IdpTokenResponse idpResponse = rest.postForObject( - "/protocol/openid-connect/token", - tokenRequest, - IdpTokenResponse.class - ); - if (idpResponse == null) { - throw new InvalidIdpTokenResponseException("The idp response cannot be null. Possible causes for this are: the 'clientId' is invalid, or the 'client' is not enabled."); - } - return idpResponse; - } -} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/PresentationService.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/PresentationService.java index a121b84a3..d592396fb 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/PresentationService.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/PresentationService.java @@ -298,6 +298,7 @@ public Map createVpWithRequiredScopes(SignedJWT innerJWT, boolea List verifiableCredentials = new ArrayList<>(); String scopeValue = getScope(jwtClaimsSet); + String[] scopes = scopeValue.split(BLANK_SEPARATOR); for (String scope : scopes) { diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/STSTokenValidationService.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/STSTokenValidationService.java index af9917297..1b05b1f25 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/STSTokenValidationService.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/service/STSTokenValidationService.java @@ -61,6 +61,10 @@ public class STSTokenValidationService { public ValidationResult validateToken(String token) { List validationResults = new ArrayList<>(); + if (token.startsWith("Bearer ")) { + token = token.substring("Bearer ".length()); + } + SignedJWT jwtSI = parseToken(token); JWTClaimsSet claimsSI = getClaimsSet(jwtSI); diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java index c38a50d64..76b06540f 100644 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/CommonUtils.java @@ -96,13 +96,6 @@ public static String getKeyString(byte[] privateKeyBytes, String keyType) { return stringWriter.toString(); } - - public static SecureTokenRequest getSecureTokenRequest(MultiValueMap map) { - final ObjectMapper objectMapper = new ObjectMapper(); - Map singleValueMap = map.toSingleValueMap(); - return objectMapper.convertValue(singleValueMap, SecureTokenRequest.class); - } - @SneakyThrows public static ECPrivateKey ecPrivateFrom(byte[] encoded) { var kf = KeyFactory.getInstance("EC"); diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/ResourceUtil.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/ResourceUtil.java new file mode 100644 index 000000000..6bbd6fd81 --- /dev/null +++ b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/utils/ResourceUtil.java @@ -0,0 +1,61 @@ +/* + * ******************************************************************************* + * 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.utils; + +import lombok.SneakyThrows; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; + +public final class ResourceUtil { + + @SneakyThrows + public static InputStream getResourceStream(String resourceName) { + var stream= ResourceUtil.class.getClassLoader().getResourceAsStream(resourceName); + if(stream == null) { + throw new IllegalArgumentException("File not found"); + } + + return stream; + } + + @SneakyThrows + public static String loadResource(String resourceName) { + StringBuilder content = new StringBuilder(); + + // load resource and return it + try (final InputStream is = ResourceUtil.class.getClassLoader().getResourceAsStream(resourceName)) { + if (is == null) { + throw new IllegalArgumentException("File not found"); + } + + final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append(System.lineSeparator()); + } + } + + return content.toString(); + } +} diff --git a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/validator/SecureTokenRequestValidator.java b/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/validator/SecureTokenRequestValidator.java deleted file mode 100644 index 1f6dd6e48..000000000 --- a/miw/src/main/java/org/eclipse/tractusx/managedidentitywallets/validator/SecureTokenRequestValidator.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * ******************************************************************************* - * 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.validator; - -import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.validation.BeanPropertyBindingResult; -import org.springframework.validation.Errors; -import org.springframework.validation.ValidationUtils; -import org.springframework.validation.Validator; - -import static org.eclipse.tractusx.managedidentitywallets.utils.CommonUtils.getSecureTokenRequest; - -public class SecureTokenRequestValidator implements Validator { - - public static final String LINKED_MULTI_VALUE_MAP_CLASS_NAME = "org.springframework.util.LinkedMultiValueMap"; - - @Override - public boolean supports(Class clazz) { - return SecureTokenRequest.class.equals(clazz) || clazz.getCanonicalName().equals(LINKED_MULTI_VALUE_MAP_CLASS_NAME); - } - - @Override - public void validate(Object target, Errors errors) { - LinkedMultiValueMap requestParams = null; - if (target instanceof LinkedMultiValueMap) { - requestParams = (LinkedMultiValueMap) target; - } - SecureTokenRequest secureTokenRequest = requestParams != null ? getSecureTokenRequest(requestParams) : (SecureTokenRequest) target; - Errors errorsHandled = new BeanPropertyBindingResult(secureTokenRequest, errors.getObjectName()); - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "audience", "audience.empty", "The 'audience' cannot be empty or missing."); - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "clientId", "client_id.empty", "The 'client_id' cannot be empty or missing."); - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "clientSecret", "client_secret.empty", "The 'client_secret' cannot be empty or missing."); - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "grantType", "grant_type.empty", "The 'grant_type' cannot be empty or missing."); - - if (secureTokenRequest.getAccessToken() != null && secureTokenRequest.getBearerAccessScope() != null) { - errorsHandled.rejectValue("accessToken", "access_token.incompatible", "The 'access_token' and the 'bearer_access_token' cannot be set together."); - errorsHandled.rejectValue("bearerAccessScope", "bearer_access_scope.incompatible", "The 'access_token' and the 'bearer_access_token' cannot be set together."); - } - if (secureTokenRequest.getAccessToken() == null && secureTokenRequest.getBearerAccessScope() == null) { - errorsHandled.rejectValue("accessToken", "access_token.incompatible", "Both the 'access_token' and the 'bearer_access_scope' are missing. At least one must be set."); - errorsHandled.rejectValue("bearerAccessScope", "bearer_access_scope.incompatible", "Both the 'access_token' and the 'bearer_access_scope' are missing. At least one must be set."); - } - if (secureTokenRequest.getAccessToken() != null) { - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "accessToken", "access_token.empty", "The 'access_token' cannot be empty or missing."); - } - if (secureTokenRequest.getBearerAccessScope() != null) { - ValidationUtils.rejectIfEmptyOrWhitespace(errorsHandled, "bearerAccessScope", "bearer_access_scope.empty", "The 'bearer_access_scope' cannot be empty or missing."); - } - } -} diff --git a/miw/src/main/resources/jsonld/IdentityMinusTrust.json b/miw/src/main/resources/jsonld/IdentityMinusTrust.json new file mode 100644 index 000000000..4a1fa6fbb --- /dev/null +++ b/miw/src/main/resources/jsonld/IdentityMinusTrust.json @@ -0,0 +1,127 @@ +{ + "@context" : { + "@version" : 1.1, + "@protected" : true, + "iatp" : "https://w3id.org/tractusx-trust/v0.8/", + "cred" : "https://www.w3.org/2018/credentials/", + "xsd" : "http://www.w3.org/2001/XMLSchema/", + "CredentialContainer" : { + "@id" : "iatp:CredentialContainer", + "@context" : { + "payload" : { + "@id" : "iatp:payload", + "@type" : "xsd:string" + } + } + }, + "CredentialMessage" : { + "@id" : "iatp:CredentialMessage", + "@context" : { + "credentials" : "iatp:credentials" + } + }, + "CredentialObject" : { + "@id" : "iatp:CredentialObject", + "@context" : { + "credentialType" : { + "@id" : "iatp:credentialType", + "@container" : "@set" + }, + "format" : "iatp:format", + "offerReason" : { + "@id" : "iatp:offerReason", + "@type" : "xsd:string" + }, + "bindingMethods" : { + "@id" : "iatp:bindingMethods", + "@type" : "xsd:string", + "@container" : "@set" + }, + "cryptographicSuites" : { + "@id" : "iatp:cryptographicSuites", + "@type" : "xsd:string", + "@container" : "@set" + }, + "issuancePolicy" : "iatp:issuancePolicy" + } + }, + "CredentialOfferMessage" : { + "@id" : "iatp:CredentialOfferMessage", + "@context" : { + "credentialIssuer" : "cred:issuer", + "credentials" : "iatp:credentials" + } + }, + "CredentialRequestMessage" : { + "@id" : "iatp:CredentialRequestMessage", + "@context" : { + "format" : "iatp:format", + "type" : "@type" + } + }, + "CredentialService" : "iatp:CredentialService", + "CredentialStatus" : { + "@id" : "iatp:CredentialStatus", + "@context" : { + "requestId" : { + "@id" : "iatp:requestId", + "@type" : "@id" + }, + "status" : { + "@id" : "iatp:status", + "@type" : "xsd:string" + } + } + }, + "IssuerMetadata" : { + "@id" : "iatp:IssuerMetadata", + "@context" : { + "credentialIssuer" : "cred:issuer", + "credentialsSupported" : { + "@id" : "iatp:credentialsSupported", + "@container" : "@set" + } + } + }, + "PresentationQueryMessage" : { + "@id" : "iatp:PresentationQueryMessage", + "@context" : { + "presentationDefinition" : { + "@id" : "iatp:presentationDefinition", + "@type" : "@json" + }, + "scope" : { + "@id" : "iatp:scope", + "@type" : "xsd:string", + "@container" : "@set" + } + } + }, + "PresentationResponseMessage" : { + "@id" : "iatp:PresentationResponseMessage", + "@context" : { + "presentation" : { + "@id" : "iatp:presentation", + "@type" : "@json" + }, + "presentationSubmission" : { + "@id" : "iatp:presentationSubmission", + "@type" : "@json" + } + } + }, + "credentials" : { + "@id" : "iatp:credentials", + "@container" : "@set" + }, + "credentialSubject" : { + "@id" : "iatp:credentialSubject", + "@type" : "cred:credentialSubject" + }, + "format" : { + "@id" : "iatp:format", + "@type" : "xsd:string" + }, + "type" : "@type" + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestContextInitializer.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestContextInitializer.java index 6c07d12f4..6cded35c8 100644 --- a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestContextInitializer.java +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/config/TestContextInitializer.java @@ -35,7 +35,7 @@ public class TestContextInitializer implements ApplicationContextInitializer { - private static final int port = findFreePort(); + public static final int port = findFreePort(); private static final KeycloakContainer KEYCLOAK_CONTAINER = new KeycloakContainer().withRealmImportFile("miw-test-realm.json"); private static final PostgreSQLContainer POSTGRE_SQL_CONTAINER = new PostgreSQLContainer<>("postgres:14.5") .withDatabaseName("integration-tests-db") diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java index 58dc11653..44cf5a751 100644 --- a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/controller/SecureTokenControllerTest.java @@ -85,16 +85,19 @@ void tokenJSON() { // when String body = """ { - "audience": "%s", - "client_id": "%s", - "client_secret": "%s", - "grant_type": "client_credentials", - "bearer_access_scope": "org.eclipse.tractusx.vc.type:BpnCredential:read" + "grantAccess": { + "scope": "read", + "credentialTypes": [ + "BpnCredential" + ], + "consumerDid": "did:web:localhost:BPNL000000000000", + "providerDid": "did:web:localhost:BPNL000000000000" + } } """; String requestBody = String.format(body, bpn, clientId, clientSecret); // then - HttpHeaders headers = new HttpHeaders(); + HttpHeaders headers = AuthenticationUtils.getValidUserHttpHeaders(); headers.put(HttpHeaders.CONTENT_TYPE, List.of(MediaType.APPLICATION_JSON_VALUE)); HttpEntity entity = new HttpEntity<>(requestBody, headers); ResponseEntity> response = testTemplate.exchange( @@ -104,33 +107,9 @@ void tokenJSON() { new ParameterizedTypeReference<>() { } ); - Assertions.assertEquals(response.getStatusCode(), HttpStatus.OK); - Assertions.assertEquals(response.getHeaders().getContentType(), MediaType.APPLICATION_JSON); + Assertions.assertEquals(HttpStatus.OK, response.getStatusCode()); + Assertions.assertEquals(MediaType.APPLICATION_JSON, response.getHeaders().getContentType()); Assertions.assertNotNull(response.getBody()); - Assertions.assertNotNull(response.getBody().getOrDefault("access_token", null)); - Assertions.assertNotNull(response.getBody().getOrDefault("expiresAt", null)); - } - - @Test - void tokenFormUrlencoded() { - // when - String body = "audience=%s&client_id=%s&client_secret=%s&grant_type=client_credentials&bearer_access_scope=org.eclipse.tractusx.vc.type:BpnCredential:read"; - String requestBody = String.format(body, bpn, clientId, clientSecret); - // then - HttpHeaders headers = new HttpHeaders(); - headers.put(HttpHeaders.CONTENT_TYPE, List.of(MediaType.APPLICATION_FORM_URLENCODED_VALUE)); - HttpEntity entity = new HttpEntity<>(requestBody, headers); - ResponseEntity> response = testTemplate.exchange( - "/api/token", - HttpMethod.POST, - entity, - new ParameterizedTypeReference<>() { - } - ); - Assertions.assertEquals(response.getStatusCode(), HttpStatus.OK); - Assertions.assertEquals(response.getHeaders().getContentType(), MediaType.APPLICATION_JSON); - Assertions.assertNotNull(response.getBody()); - Assertions.assertNotNull(response.getBody().getOrDefault("access_token", null)); - Assertions.assertNotNull(response.getBody().getOrDefault("expiresAt", null)); + Assertions.assertNotNull(response.getBody().getOrDefault("jwt", null)); } } diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseSerializationTest.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseSerializationTest.java new file mode 100644 index 000000000..43dc24fec --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/dto/PresentationResponseSerializationTest.java @@ -0,0 +1,112 @@ +/* + * ******************************************************************************* + * 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 com.github.tomakehurst.wiremock.common.StreamSources; +import lombok.SneakyThrows; +import org.eclipse.tractusx.managedidentitywallets.reader.TractusXJsonLdReader; +import org.eclipse.tractusx.ssi.lib.model.verifiable.presentation.VerifiablePresentation; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; + +import java.nio.charset.StandardCharsets; +import java.util.Map; + +/** + * This test verifies that the serialized output of the Presentation Response DTO is JsonLD and Tractus-X compliant. + *

+ * It does so by comparing the serialized output with a predefined expected output. Like a contract test. + *

+ */ +public class PresentationResponseSerializationTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + /* Please note: The order of the properties is important, as the Unit Tests does some String comparison. */ + final String Presentation = """ + { + "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", + "type": ["VerifiablePresentation", "ExamplePresentation"], + "@context": [ + "https://www.w3.org/ns/credentials/v2" + ], + "verifiableCredential": [{ + "@context": "https://www.w3.org/ns/credentials/v2", + "id": "data:application/vc+sd-jwt;QzVjV...RMjU", + "issuer": "did:example:123", + "issuanceDate": "2020-03-10T04:24:12.164Z", + "type": "VerifiableCredential", + "credentialSubject": { + "id": "did:example:456", + "degree": { + "type": "BachelorDegree", + "name": "Bachelor of Science and Arts" + } + } + }] + }"""; + + /* Please note: The order of the properties is important, as the Unit Tests does some String comparison. */ + final String ExpectedPresentationResponse = "{\n" + + " \"@context\" : [\n" + + " \"https://w3id.org/tractusx-trust/v0.8\"\n" + + " ],\n" + + " \"@type\" : [\n" + + " \"PresentationResponseMessage\"\n" + + " ],\n" + + " \"presentation\" : [\n" + + Presentation + + " ]\n" + + " }\n" + + " ]\n" + + "}\n"; + + @Test + @SneakyThrows + public void testPresentationResponseSerialization() { + var presentation = getPresentation(); + + var response = new PresentationResponseMessage(presentation); + + var serialized = MAPPER.writeValueAsString(response); + + + var serializedDocument = new StreamSources.StringInputStreamSource(serialized, StandardCharsets.UTF_8).getStream(); + var expectedDocument = new StreamSources.StringInputStreamSource(ExpectedPresentationResponse, StandardCharsets.UTF_8).getStream(); + + var reader = new TractusXJsonLdReader(); + var normalizedSerializedDocument = reader.expand(serializedDocument).toString(); + var normalizedExpectedDocument = reader.expand(expectedDocument).toString(); + + + var isEqual = normalizedSerializedDocument.equals(normalizedExpectedDocument); + + Assertions.assertTrue(isEqual, "Expected both documents to be equal.\n%s\n%s".formatted(normalizedSerializedDocument, normalizedExpectedDocument)); + } + + @SneakyThrows + private VerifiablePresentation getPresentation() { + var map = MAPPER.readValue(Presentation, Map.class); + return new VerifiablePresentation(map); + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/TokenRequestTest.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/TokenRequestTest.java new file mode 100644 index 000000000..9512f06b3 --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/TokenRequestTest.java @@ -0,0 +1,180 @@ +/* + * ******************************************************************************* + * 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.migration.identityminustrust; + +import lombok.SneakyThrows; +import org.eclipse.tractusx.managedidentitywallets.ManagedIdentityWalletsApplication; +import org.eclipse.tractusx.managedidentitywallets.config.MIWSettings; +import org.eclipse.tractusx.managedidentitywallets.config.TestContextInitializer; +import org.eclipse.tractusx.managedidentitywallets.constant.RestURI; +import org.eclipse.tractusx.managedidentitywallets.controller.SecureTokenController; +import org.eclipse.tractusx.managedidentitywallets.dto.SecureTokenRequest; +import org.eclipse.tractusx.managedidentitywallets.service.IssuersCredentialService; +import org.eclipse.tractusx.managedidentitywallets.service.WalletService; +import org.eclipse.tractusx.managedidentitywallets.utils.AuthenticationUtils; +import org.eclipse.tractusx.managedidentitywallets.utils.ResourceUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.Map; + + +@DirtiesContext +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, classes = { ManagedIdentityWalletsApplication.class }) +@ContextConfiguration(initializers = { TestContextInitializer.class }) +public class TokenRequestTest { + + private static final ObjectMapper MAPPER = new ObjectMapper(); + + private static final String TOKEN_REQUEST_WITH_SCOPE_REQUEST = "identityminustrust/messages/token_request_with_scope.json"; + private static final String TOKEN_REQUEST_WITH_TOKEN_REQUEST = "identityminustrust/messages/token_request_with_token.json"; + private static final String PRESENTATION_QUERY_REQUEST = "identityminustrust/messages/presentation_query.json"; + + @Autowired + private IssuersCredentialService issuersCredentialService; + + @Autowired + private WalletService walletService; + + @Autowired + private MIWSettings miwSettings; + + @Autowired + private TestRestTemplate restTemplate; + + @SneakyThrows + @BeforeEach + public void setup() { + walletService.createAuthorityWallet(); + + var vc = "{\n" + + " \"id\": \"did:web:foo#f255c392-82aa-483a-90a3-3c8697cd246a\",\n" + + " \"@context\": [\n" + + " \"https://www.w3.org/2018/credentials/v1\",\n" + + " \"https://w3id.org/security/suites/jws-2020/v1\"\n" + + " ],\n" + + " \"type\": [\"VerifiableCredential\", \"MembershipCredential\"],\n" + + " \"issuanceDate\": \"2021-06-16T18:56:59Z\",\n" + + " \"expirationDate\": \"2022-06-16T18:56:59Z\",\n" + + " \"issuer\": \"" + miwSettings.authorityWalletDid() + "\",\n" + + " \"credentialSubject\": {\n" + + " \"type\":\"MembershipCredential\",\n" + + " \"holderIdentifier\": \"" + miwSettings.authorityWalletDid() + "\",\n" + + " \"memberOf\":\"Catena-X\",\n" + + " \"status\":\"Active\",\n" + + " \"startTime656\":\"2021-06-16T18:56:59Z\"\n" + + " }\n" + + "}"; + + issuersCredentialService.issueCredentialUsingBaseWallet( + miwSettings.authorityWalletDid(), + MAPPER.readValue(vc, Map.class), + false, + miwSettings.authorityWalletBpn() + ); + + } + + @Test + @SneakyThrows + public void testTokenRequestWithToken() { + + final String message = getMessage(TOKEN_REQUEST_WITH_TOKEN_REQUEST); + final SecureTokenRequest data = MAPPER.readValue(message, SecureTokenRequest.class); + + final HttpHeaders headers = AuthenticationUtils.getValidUserHttpHeaders(miwSettings.authorityWalletBpn()); + final HttpEntity entity = new HttpEntity<>(data, headers); + var result = restTemplate + .postForEntity(SecureTokenController.BASE_PATH, entity, String.class); + + System.out.println("Received Response: " + result.toString()); + + Assertions.assertTrue(result.getStatusCode().is2xxSuccessful(), "Status code is not 2xx"); + Assertions.assertNotNull(MAPPER.readValue(result.getBody(), Map.class).get("jwt"), "JWT is null"); + } + + @Test + @SneakyThrows + public void testTokenRequestWithScope() { + + final String message = getMessage(TOKEN_REQUEST_WITH_SCOPE_REQUEST); + final SecureTokenRequest data = MAPPER.readValue(message, SecureTokenRequest.class); + + final HttpHeaders headers = AuthenticationUtils.getValidUserHttpHeaders(miwSettings.authorityWalletBpn()); + final HttpEntity entity = new HttpEntity<>(data, headers); + var result = restTemplate + .postForEntity(SecureTokenController.BASE_PATH, entity, String.class); + + System.out.println("Received Response: " + result.toString()); + + Assertions.assertTrue(result.getStatusCode().is2xxSuccessful(), "Status code is not 2xx"); + Assertions.assertNotNull(MAPPER.readValue(result.getBody(), Map.class).get("jwt"), "JWT is null"); + } + + @Test + @SneakyThrows + public void testPresentationQueryWithToken() { + + final String message = getMessage(TOKEN_REQUEST_WITH_SCOPE_REQUEST); + final SecureTokenRequest data = MAPPER.readValue(message, SecureTokenRequest.class); + + // set audience to used wallet + var correctAudience = "did:web:localhost%3A" + TestContextInitializer.port + ":BPNL000000000000"; + data.getSecureTokenRequestScope().get().setProviderDid(correctAudience); + data.getSecureTokenRequestScope().get().setConsumerDid(correctAudience); + + final HttpHeaders headers = AuthenticationUtils.getValidUserHttpHeaders(miwSettings.authorityWalletBpn()); + final HttpEntity entity = new HttpEntity<>(data, headers); + var result = restTemplate + .postForEntity(SecureTokenController.BASE_PATH, entity, String.class); + + System.out.println("Received Response: " + result.toString()); + + var jwt = (String) MAPPER.readValue(result.getBody(), Map.class).get("jwt"); + Assertions.assertTrue(result.getStatusCode().is2xxSuccessful(), "Status code is not 2xx"); + Assertions.assertNotNull(jwt, "JWT is null"); + + final String message2 = getMessage(PRESENTATION_QUERY_REQUEST); + final Map data2 = MAPPER.readValue(message2, Map.class); + + final HttpHeaders headers2 = new HttpHeaders(); + headers2.set(HttpHeaders.AUTHORIZATION, jwt); + final HttpEntity> entity2 = new HttpEntity<>(data2, headers2); + var result2 = restTemplate + .postForEntity(RestURI.API_PRESENTATIONS_IATP, entity2, String.class); + + System.out.println("RESULT:\n" + result2.toString()); + } + + private String getMessage(String resourceName) { + return ResourceUtil.loadResource(resourceName); + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/presentation_query.json b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/presentation_query.json new file mode 100644 index 000000000..5b0cd0345 --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/presentation_query.json @@ -0,0 +1,10 @@ +{ + "scope" : [ + "org.eclipse.tractusx.vc.type:MembershipCredential:read" + ], + "@context" : [ + "https://identity.foundation/presentation-exchange/submission/v1", + "https://w3id.org/tractusx-trust/v0.8" + ], + "@type" : "PresentationQueryMessage" +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_scope.json b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_scope.json new file mode 100644 index 000000000..cdf756717 --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_scope.json @@ -0,0 +1,10 @@ +{ + "grantAccess": { + "scope": "read", + "credentialTypes": [ + "MembershipCredential" + ], + "consumerDid": "did:web:localhost:BPNL000000000000", + "providerDid": "did:web:localhost:BPNL000000000000" + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_token.json b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_token.json new file mode 100644 index 000000000..23b83c25a --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/migration/identityminustrust/messages/token_request_with_token.json @@ -0,0 +1,8 @@ +{ + "signToken" : { + "audience" : "did:web:localhost:BPNL000000000000", + "subject" : "did:web:localhost:BPNL000000000001", + "issuer" : "did:web:localhost:BPNL000000000001", + "token" : "yJraWQiOiJkaWQ6d2ViO...dvQiWfYFU0ihkOYshnOGVeA" + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/reader/PresentationRequestReaderTest.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/reader/PresentationRequestReaderTest.java new file mode 100644 index 000000000..75ec3fd59 --- /dev/null +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/reader/PresentationRequestReaderTest.java @@ -0,0 +1,49 @@ +/* + * ******************************************************************************* + * 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.reader; + +import lombok.SneakyThrows; +import org.eclipse.tractusx.managedidentitywallets.utils.ResourceUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.InputStream; +import java.util.List; + +public class PresentationRequestReaderTest { + + private final TractusXPresentationRequestReader presentationRequestReader = new TractusXPresentationRequestReader(); + + @Test + @SneakyThrows + public void readCredentialsTest() { + + final InputStream is = ResourceUtil.getResourceStream("identityminustrust/messages/presentation_query.json"); + + final List credentialScopes = presentationRequestReader.readVerifiableCredentialScopes(is); + + final String expected = "org.eclipse.tractusx.vc.type:MembershipCredential:read"; + + System.out.printf("Found credentials: %s", credentialScopes.toString()); + Assertions.assertTrue(credentialScopes.contains(expected), "Expected %s".formatted(expected)); + } +} diff --git a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/vp/PresentationServiceTest.java b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/vp/PresentationServiceTest.java index 31768e042..7e76f6dc7 100644 --- a/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/vp/PresentationServiceTest.java +++ b/miw/src/test/java/org/eclipse/tractusx/managedidentitywallets/vp/PresentationServiceTest.java @@ -89,9 +89,6 @@ class PresentationServiceTest { @Autowired private JtiRepository jtiRepository; - @Autowired - private IssuersCredentialService issuersCredentialService; - @Autowired private ObjectMapper objectMapper; diff --git a/miw/src/test/resources/identityminustrust/messages/presentation_query.json b/miw/src/test/resources/identityminustrust/messages/presentation_query.json new file mode 100644 index 000000000..5b0cd0345 --- /dev/null +++ b/miw/src/test/resources/identityminustrust/messages/presentation_query.json @@ -0,0 +1,10 @@ +{ + "scope" : [ + "org.eclipse.tractusx.vc.type:MembershipCredential:read" + ], + "@context" : [ + "https://identity.foundation/presentation-exchange/submission/v1", + "https://w3id.org/tractusx-trust/v0.8" + ], + "@type" : "PresentationQueryMessage" +} diff --git a/miw/src/test/resources/identityminustrust/messages/token_request_with_scope.json b/miw/src/test/resources/identityminustrust/messages/token_request_with_scope.json new file mode 100644 index 000000000..10bcebc22 --- /dev/null +++ b/miw/src/test/resources/identityminustrust/messages/token_request_with_scope.json @@ -0,0 +1,10 @@ +{ + "grantAccess": { + "scope": "read", + "credentialTypes": [ + "MembershipCredential" + ], + "consumerDid": "did:web:464-203-129-213-107.ngrok-free.app:BPNL000000000000", + "providerDid": "did:web:464-203-129-213-107.ngrok-free.app:BPNL000000000000" + } +} diff --git a/miw/src/test/resources/identityminustrust/messages/token_request_with_token.json b/miw/src/test/resources/identityminustrust/messages/token_request_with_token.json new file mode 100644 index 000000000..a532a80dd --- /dev/null +++ b/miw/src/test/resources/identityminustrust/messages/token_request_with_token.json @@ -0,0 +1,8 @@ +{ + "signToken" : { + "audience" : "did:web:localhost:BPNL000000000000", + "subject" : "did:web:localhost:BPNL000000000001", + "issuer" : "did:web:localhost:BPNL000000000001", + "token" : "eyJraWQiOiJkaWQ6d2ViOmM0NjQtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMDAjYzM5MzJmZjUtOGRhNC0zZGU5LWE5NDItNjIxMjVmMzk0ZTQxIiwidHlwIjoiSldUIiwiYWxnIjoiRVMyNTZLIn0.eyJhdWQiOiJkaWQ6d2ViOmM0NjQtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMDAiLCJicG4iOiJCUE5MMDAwMDAwMDAwMDAwIiwic3ViIjoiZGlkOndlYjpjNDY0LTIwMy0xMjktMjEzLTEwNy5uZ3Jvay1mcmVlLmFwcDpCUE5MMDAwMDAwMDAwMDAwIiwibmJmIjoxNzE5NDc5NTcwLCJpc3MiOiJkaWQ6d2ViOmM0NjQtMjAzLTEyOS0yMTMtMTA3Lm5ncm9rLWZyZWUuYXBwOkJQTkwwMDAwMDAwMDAwMDAiLCJleHAiOjE3MTk0Nzk4NzAsImlhdCI6MTcxOTQ3OTU3MCwianRpIjoiZThlNWZkNzYtMDA0OC00Y2E1LTgyMjgtOTNlZDA1MmFhYzMzIn0.Gmd7u0sOjVXde9nZeQlVbXo65xB1tZ2VBy6a1gZG-z9IrhdM0cZuXIaS2IUY3bydvQiWfYFU0ihkOYshnOGVeA" + } +}