Skip to content

Commit

Permalink
Hotfix/v1.0.0 3 (#26)
Browse files Browse the repository at this point in the history
* Change the versioning of the endpoints from v2 to v1.

* Update CHANGELOG.md

* ADD dynamic VP expiration

* FIX application yaml

* FIX test

* ADD tests

* FIX version and ADD changelog

* CHANGE version to v1.1.1

* changes

* Update application.yml

* Update VerifiablePresentationController.java

* return an empty list instead of an error

* changes

* Update build.gradle

* Update VerifiablePresentationControllerTest.java

* update zoneTIme

* Update status code to 404 when user don't have credentials

* Solve requested changes

* dome changes

* Test

* test

* Added a exception to ExceptionHandler

* Rename exception

* rename property

* Update exception

* Update DEFAULT_VC_TYPES_FOR_DOME_VERIFIER

* Return the available format without modifiying the original vc_json

* Tests

* Test for patterns

* test

* Revert "test"

This reverts commit 5331044.

* test

* Add again the LearCredential type because we will be able to login on Dome portal with the LEAR, and added error management for  authorisation response dome

* Changes

* Update UserDataServiceImpl.java

* Use only one model of credentialBasicInfo

* Update application.yml

* added todo

---------

Co-authored-by: AzureAD\JiaboWang <jiabo.wang@in2.es>
  • Loading branch information
rubenmodamioin2 and jiabowangin2 committed Apr 15, 2024
1 parent 3a3620d commit 9017978
Show file tree
Hide file tree
Showing 37 changed files with 776 additions and 190 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Introduced the abstraction of the configuration and the vault
- Compatibility with the attestation exchange of the DOME marketplace.

## [v1.1.0](https://github.com/in2workspace/wallet-server/releases/tag/v1.1.1) - 2024-04-02
## [v1.1.1](https://github.com/in2workspace/wallet-server/releases/tag/v1.1.1) - 2024-04-02
### Fixed
- Change the versioning of the api endpoints from v2 to v1
- Change hardcoded verifiable presentation expiration to dynamic variable
- Change hardcoded verifiable presentation expiration to dynamic variable

## [v1.1.2](https://github.com/in2workspace/wallet-server/releases/tag/v1.1.2) - 2024-04-04
### Fixed
- Change the return value from a exception to an empty list when the user don't have any credential
- Added the logic for selecting the credential that is wanted to be presented during the DOME presentation flow.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = 'es.in2'
version = '1.1.1'
version = '1.1.2'

java {
sourceCompatibility = '17'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package es.in2.wallet.application.service;

import es.in2.wallet.domain.model.VcSelectorRequest;
import es.in2.wallet.domain.model.VcSelectorResponse;
import reactor.core.publisher.Mono;


public interface DomeAttestationExchangeService {
Mono<Void> getSelectableCredentialsRequiredToBuildThePresentation(String processId, String authorizationToken, String qrContent);
Mono<VcSelectorRequest> getSelectableCredentialsRequiredToBuildThePresentation(String processId, String authorizationToken, String qrContent);
public Mono<Void> buildAndSendVerifiablePresentationWithSelectedVCsForDome(String processId, String authorizationToken, VcSelectorResponse vcSelectorResponse);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package es.in2.wallet.application.service;

import es.in2.wallet.domain.model.CredentialsBasicInfoWithExpirationDate;
import es.in2.wallet.domain.model.CredentialsBasicInfo;
import reactor.core.publisher.Mono;

import java.util.List;

public interface UserDataUseCaseService {
public Mono<List<CredentialsBasicInfoWithExpirationDate>> getUserVCs(String processId, String userId);
public Mono<List<CredentialsBasicInfo>> getUserVCs(String processId, String userId);
Mono<Void> deleteVerifiableCredentialById(String processId,String credentialId, String userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import es.in2.wallet.application.service.AttestationExchangeService;
import es.in2.wallet.domain.exception.FailedDeserializingException;
import es.in2.wallet.domain.model.AuthorizationRequest;
import es.in2.wallet.domain.model.CredentialsBasicInfo;
import es.in2.wallet.domain.model.VcSelectorRequest;
import es.in2.wallet.domain.model.VcSelectorResponse;
import es.in2.wallet.domain.model.*;
import es.in2.wallet.domain.service.*;
import es.in2.wallet.application.port.BrokerService;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
package es.in2.wallet.application.service.impl;

import es.in2.wallet.application.service.DomeAttestationExchangeService;
import es.in2.wallet.domain.model.VcSelectorRequest;
import es.in2.wallet.domain.model.VcSelectorResponse;
import es.in2.wallet.domain.service.AuthorizationRequestService;
import es.in2.wallet.domain.service.DidKeyGeneratorService;
import es.in2.wallet.domain.service.AuthorizationResponseService;
import es.in2.wallet.domain.service.DomeVpTokenService;
import es.in2.wallet.domain.service.PresentationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class DomeAttestationExchangeServiceImpl implements DomeAttestationExchangeService {
private final AuthorizationRequestService authorizationRequestService;
private final DomeVpTokenService domeVpTokenService;
private final DidKeyGeneratorService didKeyGeneratorService;
private final PresentationService presentationService;
private final AuthorizationResponseService authorizationResponseService;


@Override
public Mono<Void> getSelectableCredentialsRequiredToBuildThePresentation(String processId, String authorizationToken, String qrContent) {
public Mono<VcSelectorRequest> getSelectableCredentialsRequiredToBuildThePresentation(String processId, String authorizationToken, String qrContent) {
log.info("ProcessID: {} - Processing a Verifiable Credential Login Request", processId);
// Get Authorization Request executing the VC Login Request
return authorizationRequestService.getAuthorizationRequestFromAuthorizationRequestClaims(processId, qrContent)
// Check which Verifiable Credentials are selectable
.flatMap(authorizationRequest -> domeVpTokenService.getVpRequest(processId,authorizationToken,authorizationRequest));
}
@Override
public Mono<Void> buildAndSendVerifiablePresentationWithSelectedVCsForDome(String processId, String authorizationToken, VcSelectorResponse vcSelectorResponse) {
// Get the Verifiable Credentials which will be used for the Presentation from the Wallet Data Service
return presentationService.createEncodedVerifiablePresentationForDome(processId,authorizationToken,vcSelectorResponse)
.flatMap(vpToken -> authorizationResponseService.sendDomeAuthorizationResponse(vpToken,vcSelectorResponse));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import es.in2.wallet.application.port.BrokerService;
import es.in2.wallet.application.port.VaultService;
import es.in2.wallet.application.service.UserDataUseCaseService;
import es.in2.wallet.domain.model.CredentialsBasicInfoWithExpirationDate;
import es.in2.wallet.domain.exception.NoSuchVerifiableCredentialException;
import es.in2.wallet.domain.model.CredentialsBasicInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -27,10 +28,10 @@ public class UserDataUseCaseServiceImpl implements UserDataUseCaseService {
* @param userId The unique identifier of the user whose VCs are to be retrieved.
*/
@Override
public Mono<List<CredentialsBasicInfoWithExpirationDate>> getUserVCs(String processId, String userId) {
public Mono<List<CredentialsBasicInfo>> getUserVCs(String processId, String userId) {
return brokerService.getEntityById(processId, userId).flatMap(optionalEntity -> optionalEntity.map(userDataService::getUserVCsInJson).orElseGet(() -> {
log.error("User with ID {} has no entity or credentials yet.", userId);
return Mono.error(new RuntimeException("There's no credential available."));
return Mono.error(new NoSuchVerifiableCredentialException("There is no credential available"));
})).doOnSuccess(list -> log.info("Retrieved VCs in JSON for userId: {}", userId)).onErrorResume(Mono::error);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package es.in2.wallet.domain.exception;

public class InvalidPinException extends Exception {
public InvalidPinException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,27 @@ public Mono<GlobalErrorMessage> parseErrorException(ParseErrorException ex, Serv
.path(path)
.build());
}
@ExceptionHandler(NoSuchVerifiableCredentialException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
@ResponseBody
public Mono<GlobalErrorMessage> noSuchVerifiableCredentialException(NoSuchVerifiableCredentialException ex, ServerHttpRequest request) {
String path = String.valueOf(request.getPath());
return Mono.just(GlobalErrorMessage.builder()
.title("NoSuchVerifiableCredentialException")
.message(ex.getMessage())
.path(path)
.build());
}

@ExceptionHandler(InvalidPinException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ResponseBody
public Mono<GlobalErrorMessage> invalidCredentialsException(InvalidPinException ex, ServerHttpRequest request) {
String path = String.valueOf(request.getPath());
return Mono.just(GlobalErrorMessage.builder()
.title("InvalidCredentialsException")
.message(ex.getMessage())
.path(path)
.build());
}
}
12 changes: 10 additions & 2 deletions src/main/java/es/in2/wallet/domain/model/CredentialsBasicInfo.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
package es.in2.wallet.domain.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Builder;

import java.time.ZonedDateTime;
import java.util.List;

import static es.in2.wallet.domain.util.MessageUtils.*;

@Builder
public record CredentialsBasicInfo(
@JsonProperty("id") String id,
@JsonProperty("vcType") List<String> vcType,
@JsonProperty("credentialSubject") JsonNode credentialSubject
@JsonProperty("type") List<String> vcType,
@JsonProperty(AVAILABLE_FORMATS) List<String> availableFormats,
@JsonProperty(CREDENTIAL_SUBJECT) JsonNode credentialSubject,
@JsonProperty(EXPIRATION_DATE)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = ISO_8601_DATE_PATTERN)
ZonedDateTime expirationDate
) {
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@

public interface AuthorizationResponseService {
Mono<String> buildAndPostAuthorizationResponseWithVerifiablePresentation(String processId, VcSelectorResponse vcSelectorResponse, String verifiablePresentation, String authorizationToken) throws JsonProcessingException;
Mono<Void> sendDomeAuthorizationResponse(String vpToken, VcSelectorResponse vcSelectorResponse);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package es.in2.wallet.domain.service;

import es.in2.wallet.domain.model.AuthorizationRequest;
import es.in2.wallet.domain.model.VcSelectorRequest;
import reactor.core.publisher.Mono;

public interface DomeVpTokenService {
Mono<Void> getVpRequest(String processId, String authorizationToken, AuthorizationRequest authorizationRequest);
Mono<VcSelectorRequest> getVpRequest(String processId, String authorizationToken, AuthorizationRequest authorizationRequest);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import es.in2.wallet.domain.model.CredentialResponse;
import es.in2.wallet.domain.model.CredentialsBasicInfo;
import es.in2.wallet.domain.model.CredentialsBasicInfoWithExpirationDate;
import es.in2.wallet.domain.model.VCAttribute;
import reactor.core.publisher.Mono;

Expand All @@ -12,7 +11,7 @@ public interface UserDataService {

Mono<String> createUserEntity(String id);
Mono<String> saveVC(String userEntity, List<CredentialResponse> credentials);
Mono<List<CredentialsBasicInfoWithExpirationDate>> getUserVCsInJson(String userEntity);
Mono<List<CredentialsBasicInfo>> getUserVCsInJson(String userEntity);

Mono<List<VCAttribute>> getVerifiableCredentialsByFormat(String userEntity, String format);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import es.in2.wallet.domain.exception.FailedDeserializingException;
import es.in2.wallet.domain.model.*;
import es.in2.wallet.domain.service.AuthorizationResponseService;
import es.in2.wallet.domain.util.ApplicationUtils;
import es.in2.wallet.domain.util.MessageUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -21,12 +20,13 @@
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;

import static es.in2.wallet.domain.util.ApplicationUtils.postRequest;
import static es.in2.wallet.domain.util.MessageUtils.CONTENT_TYPE;
import static es.in2.wallet.domain.util.MessageUtils.CONTENT_TYPE_URL_ENCODED_FORM;


@Slf4j
@Service
Expand All @@ -43,6 +43,24 @@ public Mono<String> buildAndPostAuthorizationResponseWithVerifiablePresentation(
.flatMap(presentationSubmissionString -> postAuthorizationResponse(processId, vcSelectorResponse, verifiablePresentation, presentationSubmissionString, authorizationToken));
}

@Override
public Mono<Void> sendDomeAuthorizationResponse(String vpToken, VcSelectorResponse vcSelectorResponse) {
String body = "vp_token=" + vpToken;
List<Map.Entry<String, String>> headers = new ArrayList<>();
headers.add(new AbstractMap.SimpleEntry<>(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM));

String urlWithState = vcSelectorResponse.redirectUri() + "?state=" + vcSelectorResponse.state();

return postRequest(urlWithState, headers,body).flatMap(message ->
{
if (!message.equals("{}")) {
return Mono.error(new RuntimeException("There was an error during the attestation exchange, error: " + message));
} else {
return Mono.empty();
}
}).then();
}

private Mono<DescriptorMap> generateDescriptorMapping(String verifiablePresentationString) throws JsonProcessingException {
// Parse the Verifiable Presentation
return parseVerifiablePresentationFromString(verifiablePresentationString)
Expand Down Expand Up @@ -161,7 +179,7 @@ private Mono<String> postAuthorizationResponse(String processId, VcSelectorRespo
String verifiablePresentation, String presentationSubmissionString, String authorizationToken) {
// Headers
List<Map.Entry<String, String>> headers = List.of(
Map.entry(MessageUtils.CONTENT_TYPE, MessageUtils.CONTENT_TYPE_URL_ENCODED_FORM),
Map.entry(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM),
Map.entry(MessageUtils.HEADER_AUTHORIZATION, MessageUtils.BEARER + authorizationToken));
// Build URL encoded form data request body
Map<String, String> formDataMap = Map.of(
Expand All @@ -173,7 +191,7 @@ private Mono<String> postAuthorizationResponse(String processId, VcSelectorRespo
.map(entry -> URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
// Post request
return ApplicationUtils.postRequest(vcSelectorResponse.redirectUri(), headers, xWwwFormUrlencodedBody)
return postRequest(vcSelectorResponse.redirectUri(), headers, xWwwFormUrlencodedBody)
.doOnSuccess(response -> log.info("ProcessID: {} - Authorization Response: {}", processId, response))
.onErrorResume(e -> Mono.error(new FailedCommunicationException("Error while fetching Credential Issuer Metadata from the Issuer")));
}
Expand Down
Loading

0 comments on commit 9017978

Please sign in to comment.