Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/v1.0.0 3 #26

Merged
merged 41 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
41a4f2d
Change the versioning of the endpoints from v2 to v1.
rubenmodamioin2 Mar 26, 2024
4c2975e
Update CHANGELOG.md
rubenmodamioin2 Mar 26, 2024
c4dc818
ADD dynamic VP expiration
jiabowangin2 Mar 28, 2024
3a7d691
FIX application yaml
jiabowangin2 Mar 28, 2024
eb41519
FIX test
jiabowangin2 Mar 28, 2024
a14f249
ADD tests
jiabowangin2 Mar 28, 2024
f802145
Merge remote-tracking branch 'origin/hotfix/v1.1.0' into hotfix/v1.1.0-2
jiabowangin2 Apr 2, 2024
a90762b
FIX version and ADD changelog
jiabowangin2 Apr 2, 2024
c9ea3a8
CHANGE version to v1.1.1
jiabowangin2 Apr 2, 2024
183f089
changes
rubenmodamioin2 Apr 3, 2024
3941584
Update application.yml
rubenmodamioin2 Apr 3, 2024
0330856
Update VerifiablePresentationController.java
rubenmodamioin2 Apr 3, 2024
b0ac4b3
return an empty list instead of an error
rubenmodamioin2 Apr 4, 2024
332c98c
changes
rubenmodamioin2 Apr 4, 2024
f4f6513
Merge branch 'main' into hotfix/v1.0.0-3
rubenmodamioin2 Apr 4, 2024
1f02eba
Update build.gradle
rubenmodamioin2 Apr 4, 2024
c1bf410
Update VerifiablePresentationControllerTest.java
rubenmodamioin2 Apr 4, 2024
b5ad629
update zoneTIme
rubenmodamioin2 Apr 4, 2024
353419d
Update status code to 404 when user don't have credentials
rubenmodamioin2 Apr 4, 2024
0d0724f
Solve requested changes
rubenmodamioin2 Apr 4, 2024
877c2f0
Merge branch 'hotfix/v1.0.0-3' into hotfix/v1.0.0-4
rubenmodamioin2 Apr 4, 2024
630cf11
dome changes
rubenmodamioin2 Apr 4, 2024
8164cdd
Test
rubenmodamioin2 Apr 4, 2024
5cd6027
test
rubenmodamioin2 Apr 4, 2024
b42b10b
Added a exception to ExceptionHandler
rubenmodamioin2 Apr 5, 2024
3bcd0df
Rename exception
rubenmodamioin2 Apr 5, 2024
9fda825
rename property
rubenmodamioin2 Apr 5, 2024
e6528c1
Update exception
rubenmodamioin2 Apr 5, 2024
1e1762c
Update DEFAULT_VC_TYPES_FOR_DOME_VERIFIER
rubenmodamioin2 Apr 8, 2024
ff06e23
Return the available format without modifiying the original vc_json
rubenmodamioin2 Apr 9, 2024
32d1013
Tests
rubenmodamioin2 Apr 9, 2024
abc1e24
Test for patterns
rubenmodamioin2 Apr 9, 2024
5331044
test
rubenmodamioin2 Apr 9, 2024
ff686b6
Revert "test"
rubenmodamioin2 Apr 9, 2024
6e13367
test
rubenmodamioin2 Apr 9, 2024
02d684f
Add again the LearCredential type because we will be able to login on…
rubenmodamioin2 Apr 10, 2024
a05bfa4
Changes
rubenmodamioin2 Apr 10, 2024
466fe49
Update UserDataServiceImpl.java
rubenmodamioin2 Apr 10, 2024
46d5058
Use only one model of credentialBasicInfo
rubenmodamioin2 Apr 12, 2024
61407ce
Update application.yml
rubenmodamioin2 Apr 12, 2024
287ad84
added todo
rubenmodamioin2 Apr 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
public record CredentialsBasicInfoWithExpirationDate(
@JsonProperty("id") String id,
@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)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,15 @@ public Mono<Void> sendDomeAuthorizationResponse(String vpToken, VcSelectorRespon

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

return postRequest(urlWithState, headers,body)
.onErrorResume(e -> Mono.error(new FailedCommunicationException("Error while sending Vp Token Response")))
.then();
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 {
rubenmodamioin2 marked this conversation as resolved.
Show resolved Hide resolved
return Mono.empty();
}
}).then();
}

private Mono<DescriptorMap> generateDescriptorMapping(String verifiablePresentationString) throws JsonProcessingException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,17 +239,33 @@ public Mono<List<CredentialsBasicInfoWithExpirationDate>> getUserVCsInJson(Strin
LinkedHashMap<?, ?> vcDataValue = (LinkedHashMap<?, ?>) item.value();
JsonNode jsonNode = objectMapper.convertValue(vcDataValue, JsonNode.class);

return getVcTypeListFromVcJson(jsonNode)
.map(vcTypeList -> {
ZonedDateTime expirationDate = null;
if (jsonNode.has(EXPIRATION_DATE) && !jsonNode.get(EXPIRATION_DATE).isNull()) {
expirationDate = parseZonedDateTime(jsonNode.get(EXPIRATION_DATE).asText());
}
return new CredentialsBasicInfoWithExpirationDate(item.id(), vcTypeList, jsonNode.get(CREDENTIAL_SUBJECT), expirationDate);
});
Mono<List<String>> availableFormatsMono = getAvailableFormatListById(item.id(), userEntity);

rubenmodamioin2 marked this conversation as resolved.
Show resolved Hide resolved
return Mono.zip(
getVcTypeListFromVcJson(jsonNode),
availableFormatsMono,
Mono.just(jsonNode)
).flatMap(tuple -> {
List<String> vcTypeList = tuple.getT1();
List<String> availableFormats = tuple.getT2();
JsonNode credentialSubject = tuple.getT3().get(CREDENTIAL_SUBJECT);

ZonedDateTime expirationDate = null;
if (jsonNode.has(EXPIRATION_DATE) && !jsonNode.get(EXPIRATION_DATE).isNull()) {
expirationDate = parseZonedDateTime(jsonNode.get(EXPIRATION_DATE).asText());
}
return Mono.just(new CredentialsBasicInfoWithExpirationDate(
item.id(),
vcTypeList,
availableFormats,
credentialSubject,
expirationDate
));
});
}).collectList().onErrorResume(NoSuchVerifiableCredentialException.class, Mono::error);
}


/**
* This method parses a date-time string into a ZonedDateTime object using a custom DateTimeFormatter.
* The formatter is built with Locale.US to ensure consistency in parsing text-based elements of the date-time,
Expand Down Expand Up @@ -428,6 +444,20 @@ private Mono<List<String>> getVcTypeListFromVcJson(JsonNode jsonNode) {
}
}

/**
* Extracts a list of VC available format from a VC id.
*
* @param credentialId The id of the VC.
*/
private Mono<List<String>> getAvailableFormatListById(String credentialId,String userEntity) {
return serializeUserEntity(userEntity).flatMap(user -> {
List<VCAttribute> vcAttributeList = user.vcs().value().stream().filter(vc -> vc.id().equals(credentialId)&& !vc.type().equals(VC_JSON)).toList();
List<String> availableFormats = new ArrayList<>();
vcAttributeList.forEach(cred -> availableFormats.add(cred.type()));
return Mono.just(availableFormats);
});
}

/**
* Retrieves a specific Verifiable Credential by its ID and format for a user entity.
*
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/es/in2/wallet/domain/util/MessageUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ private MessageUtils() {
public static final String JWT_VC = "jwt_vc";
public static final String JWT_VC_JSON = "jwt_vc_json";
public static final String JWT_VP = "jwt_vp";
public static final String AVAILABLE_FORMATS = "available_formats";
public static final String ALLOWED_METHODS = "*";
public static final String GLOBAL_ENDPOINTS_API = "/api/v1/**";
public static final Pattern LOGIN_REQUEST_PATTERN = Pattern.compile("(https|http)\\S*(authentication-request|authentication-requests)\\S*");
Expand All @@ -63,6 +64,6 @@ private MessageUtils() {
public static final Pattern OPENID_AUTHENTICATION_REQUEST_PATTERN = Pattern.compile("openid://\\S*");

public static final String ISO_8601_DATE_PATTERN = "yyyy-MM-dd'T'HH:mm:ssX";
public static final List<String> DEFAULT_VC_TYPES_FOR_DOME_VERIFIER = List.of("LegalPersonCredential", "LEARCredentialEmployee");
public static final List<String> DEFAULT_VC_TYPES_FOR_DOME_VERIFIER = List.of("LegalPersonCredential","LEARCredentialEmployee");
public static final List<String> DEFAULT_SCOPE_FOR_DOME_VERIFIER = List.of("didRead", "defaultScope");
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,32 @@ private Mono<String> generateEbsiDid() {
log.debug(headers.toString());

headers.add(new AbstractMap.SimpleEntry<>(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM));
String clientSecret;

String clientSecret = appConfig.getIdentityProviderClientSecret().trim();
String decodedSecret;

try {
byte[] decodedBytes = Base64.getDecoder().decode(appConfig.getIdentityProviderClientSecret());
clientSecret = new String(decodedBytes).trim();
// Attempt to decode the clientSecret assuming it is Base64 encoded.
byte[] decodedBytes = Base64.getDecoder().decode(clientSecret);
decodedSecret = new String(decodedBytes, StandardCharsets.UTF_8);

// Check if re-encoding the decoded result gives us the original string.
String reEncodedSecret = Base64.getEncoder().encodeToString(decodedSecret.getBytes(StandardCharsets.UTF_8)).trim();
if (!clientSecret.equals(reEncodedSecret)) {
// If re-encoding the decoded text does not match the original string,
// assume the original was not in Base64 and use it as it was.
decodedSecret = clientSecret;
}
} catch (IllegalArgumentException ex) {
clientSecret = appConfig.getIdentityProviderClientSecret().trim();
// If an error occurs during decoding, assume the string was not in Base64.
decodedSecret = clientSecret;
}

String body = "grant_type=" + URLEncoder.encode("password", StandardCharsets.UTF_8) +
"&username=" + URLEncoder.encode(appConfig.getIdentityProviderUsername(), StandardCharsets.UTF_8) +
"&password=" + URLEncoder.encode(appConfig.getIdentityProviderPassword(), StandardCharsets.UTF_8) +
"&client_id=" + URLEncoder.encode(appConfig.getIdentityProviderClientId(), StandardCharsets.UTF_8) +
"&client_secret=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8);
"&client_secret=" + URLEncoder.encode(decodedSecret, StandardCharsets.UTF_8);

return Mono.delay(Duration.ofSeconds(30))
.then(postRequest(appConfig.getIdentityProviderUrl(), headers, body))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ void getUserVCs_UserExists_ReturnsVCs() throws JsonProcessingException {
Optional<String> userEntity = Optional.of(userEntityString);


String json = "{\"id\":\"subjectId\"}";
String jsonSubject = "{\"id\":\"subjectId\"}";
ObjectMapper objectMapper2 = new ObjectMapper();
JsonNode credentialSubject = objectMapper2.readTree(json);
JsonNode credentialSubject = objectMapper2.readTree(jsonSubject);

List<CredentialsBasicInfoWithExpirationDate> expectedCredentials = List.of(new CredentialsBasicInfoWithExpirationDate("id1", List.of("type"), credentialSubject, ZonedDateTime.now()));
List<CredentialsBasicInfoWithExpirationDate> expectedCredentials = List.of(new CredentialsBasicInfoWithExpirationDate("id1", List.of("type"), List.of("jwt_vc","cwt_vc"),credentialSubject, ZonedDateTime.now()));

when(brokerService.getEntityById(processId, userId)).thenReturn(Mono.just(userEntity));
when(userDataService.getUserVCsInJson(anyString())).thenReturn(Mono.just(expectedCredentials));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,15 @@ void sendDomeAuthorizationResponse_Success() {
.state("abc123")
.build();

when(postRequest(anyString(), anyList(), anyString())).thenReturn(Mono.just("Success"));
when(postRequest(anyString(), anyList(), anyString())).thenReturn(Mono.just("{}"));

StepVerifier.create(authorizationResponseService.sendDomeAuthorizationResponse(vpToken, vcSelectorResponse))
.verifyComplete();
}
}

@Test
void sendDomeAuthorizationResponse_ErrorHandling() {
void sendDomeAuthorizationResponse_RuntimeExceptionError() {
try (MockedStatic<ApplicationUtils> ignored = Mockito.mockStatic(ApplicationUtils.class)) {
String vpToken = "vpToken123";
VcSelectorResponse vcSelectorResponse = VcSelectorResponse.builder()
Expand All @@ -144,8 +144,31 @@ void sendDomeAuthorizationResponse_ErrorHandling() {
when(postRequest(anyString(), anyList(), anyString())).thenReturn(Mono.error(new RuntimeException("Network error")));

StepVerifier.create(authorizationResponseService.sendDomeAuthorizationResponse(vpToken, vcSelectorResponse))
.expectErrorMatches(throwable -> throwable instanceof FailedCommunicationException &&
throwable.getMessage().contains("Error while sending Vp Token Response"))
.expectError(RuntimeException.class)
.verify();
}
}

@Test
void sendDomeAuthorizationResponse_ErrorHandling() {
try (MockedStatic<ApplicationUtils> ignored = Mockito.mockStatic(ApplicationUtils.class)) {
String vpToken = "vpToken123";
VcSelectorResponse vcSelectorResponse = VcSelectorResponse.builder()
.redirectUri("https://example.com/redirect")
.state("abc123")
.build();
String errorMessage = """
{
"summary": "invalid_vc"
}
""";

// Simula un error durante el envío de la respuesta
when(postRequest(anyString(), anyList(), anyString())).thenReturn(Mono.just(errorMessage));

StepVerifier.create(authorizationResponseService.sendDomeAuthorizationResponse(vpToken, vcSelectorResponse))
.expectErrorMatches(throwable -> throwable instanceof RuntimeException &&
throwable.getMessage().contains("There was an error during the attestation exchange, error: " + errorMessage))
.verify();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,45 @@ void getVpRequestShouldReturnVcSelectorRequest() {
verify(brokerService).getEntityById(processId, userId);
}
}
@Test
void getVpRequestShouldReturnVcSelectorRequestWithDomeScope() {
try (MockedStatic<ApplicationUtils> ignored = Mockito.mockStatic(ApplicationUtils.class)){
String processId = "processId";
String authorizationToken = "authToken";
AuthorizationRequest authorizationRequest = mock(AuthorizationRequest.class);
when(authorizationRequest.scope()).thenReturn(Arrays.asList("didRead", "defaultScope"));
when(authorizationRequest.redirectUri()).thenReturn("https://redirectUri.com");
when(authorizationRequest.state()).thenReturn("state123");

String userId = "userId";
when(getUserIdFromToken(authorizationToken)).thenReturn(Mono.just(userId));

String userEntity = "userEntityId";
when(brokerService.getEntityById(processId, userId)).thenReturn(Mono.just(Optional.of(userEntity)));

// Ajusta aquí para usar CredentialsBasicInfo
List<CredentialsBasicInfo> selectableVCs = List.of(
new CredentialsBasicInfo("vcId1", List.of("vcType1"), JsonNodeFactory.instance.objectNode().put("example", "data"))
);
when(userDataService.getSelectableVCsByVcTypeList(anyList(), eq(userEntity))).thenReturn(Mono.just(selectableVCs));

VcSelectorRequest expectedVcSelectorRequest = VcSelectorRequest.builder()
.selectableVcList(selectableVCs)
.redirectUri("https://redirectUri.com")
.state("state123")
.build();

StepVerifier.create(domeVpTokenService.getVpRequest(processId, authorizationToken, authorizationRequest))
.expectNextMatches(vcSelectorRequest ->
vcSelectorRequest.selectableVcList().equals(expectedVcSelectorRequest.selectableVcList()) &&
vcSelectorRequest.redirectUri().equals(expectedVcSelectorRequest.redirectUri()) &&
vcSelectorRequest.state().equals(expectedVcSelectorRequest.state())
)
.verifyComplete();

verify(userDataService).getSelectableVCsByVcTypeList(anyList(), eq(userEntity));
verify(brokerService).getEntityById(processId, userId);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,32 @@ void getPreAuthorizedTokenWithPinTest() throws JsonProcessingException {
.verifyComplete();
}
}
@Test
void getPreAuthorizedTokenWithPinInvalidPinException () throws JsonProcessingException {
try (MockedStatic<ApplicationUtils> ignored = Mockito.mockStatic(ApplicationUtils.class)) {
String processId = "123";
String token = "ey123";
String userId = "user123";
String userPin = "1234";
String tokenResponseString = "token response";
CredentialOffer.Grant.PreAuthorizedCodeGrant preAuthorizedCodeGrant = CredentialOffer.Grant.PreAuthorizedCodeGrant.builder()
.preAuthorizedCode("321").userPinRequired(true).build();
CredentialOffer.Grant grant = CredentialOffer.Grant.builder().preAuthorizedCodeGrant(preAuthorizedCodeGrant).build();
CredentialOffer credentialOffer = CredentialOffer.builder().grant(grant).build();
AuthorisationServerMetadata authorisationServerMetadata = AuthorisationServerMetadata.builder().tokenEndpoint("/token").build();
List<Map.Entry<String, String>> headers = List.of(Map.entry(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM));

when(getUserIdFromToken(token)).thenReturn(Mono.just(userId));
when(sessionManager.getSession(userId)).thenReturn(Mono.just(mockSession));
when(pinRequestWebSocketHandler.getPinResponses(userId)).thenReturn(Flux.just(userPin));
when(postRequest(eq(authorisationServerMetadata.tokenEndpoint()), eq(headers), anyString()))
.thenReturn(Mono.just(tokenResponseString));
when(objectMapper.readValue(tokenResponseString, TokenResponse.class)).thenThrow(new RuntimeException());

StepVerifier.create(tokenService.getPreAuthorizedToken(processId,credentialOffer,authorisationServerMetadata,token))
.expectError(InvalidPinException.class)
.verify();
}
}

}
Loading
Loading