mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Always Return Array of Credentilas for Credential Responses (#40409)
Closes #39283 Signed-off-by: forkimenjeckayang <forkimenjeckayang@gmail.com> Co-authored-by: Francis Pouatcha <francis.pouatcha@adorsys.com>
This commit is contained in:
parent
eb7ce6ae15
commit
178b893492
@ -408,7 +408,7 @@ public class OID4VCIssuerEndpoint {
|
||||
|
||||
Object theCredential = getCredential(authResult, supportedCredentialConfiguration, credentialRequestVO);
|
||||
if (SUPPORTED_FORMATS.contains(requestedFormat)) {
|
||||
responseVO.setCredential(theCredential);
|
||||
responseVO.addCredential(theCredential);
|
||||
} else {
|
||||
throw new BadRequestException(getErrorResponse(ErrorType.UNSUPPORTED_CREDENTIAL_TYPE));
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
package org.keycloak.protocol.oid4vc.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@ -29,18 +32,37 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class CredentialResponse {
|
||||
|
||||
// concrete type depends on the format
|
||||
private Object credential;
|
||||
@JsonProperty("credentials")
|
||||
private List<Credential> credentials;
|
||||
|
||||
@JsonProperty("transaction_id")
|
||||
private String transactionId;
|
||||
|
||||
@JsonProperty("notification_id")
|
||||
private String notificationId;
|
||||
|
||||
public Object getCredential() {
|
||||
return credential;
|
||||
public List<Credential> getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public CredentialResponse setCredential(Object credential) {
|
||||
this.credential = credential;
|
||||
public CredentialResponse setCredentials(List<Credential> credentials) {
|
||||
this.credentials = credentials;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addCredential(Object credential) {
|
||||
if (this.credentials == null) {
|
||||
this.credentials = new ArrayList<>();
|
||||
}
|
||||
this.credentials.add(new Credential().setCredential(credential));
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public CredentialResponse setTransactionId(String transactionId) {
|
||||
this.transactionId = transactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -52,4 +74,22 @@ public class CredentialResponse {
|
||||
this.notificationId = notificationId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class to represent a single credential object within the credentials array.
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public static class Credential {
|
||||
@JsonProperty("credential")
|
||||
private Object credential;
|
||||
|
||||
public Object getCredential() {
|
||||
return credential;
|
||||
}
|
||||
|
||||
public Credential setCredential(Object credential) {
|
||||
this.credential = credential;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,8 +408,14 @@ public abstract class OID4VCIssuerEndpointTest extends OID4VCTest {
|
||||
|
||||
protected static class CredentialResponseHandler {
|
||||
protected void handleCredentialResponse(CredentialResponse credentialResponse) throws VerificationException {
|
||||
assertNotNull("The credential should have been responded.", credentialResponse.getCredential());
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialResponse.getCredential(), JsonWebToken.class).getToken();
|
||||
assertNotNull("The credentials array should be present in the response.", credentialResponse.getCredentials());
|
||||
assertFalse("The credentials array should not be empty.", credentialResponse.getCredentials().isEmpty());
|
||||
|
||||
// Get the first credential from the array (maintaining compatibility with single credential tests)
|
||||
CredentialResponse.Credential credentialObj = credentialResponse.getCredentials().get(0);
|
||||
assertNotNull("The first credential in the array should not be null.", credentialObj);
|
||||
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialObj.getCredential(), JsonWebToken.class).getToken();
|
||||
assertEquals("did:web:test.org", jsonWebToken.getIssuer());
|
||||
VerifiableCredential credential = JsonSerialization.mapper.convertValue(jsonWebToken.getOtherClaims().get("vc"), VerifiableCredential.class);
|
||||
assertEquals(List.of("VerifiableCredential"), credential.getType());
|
||||
|
||||
@ -333,7 +333,7 @@ public class OID4VCJWTIssuerEndpointTest extends OID4VCIssuerEndpointTest {
|
||||
assertEquals("The credential request should be answered successfully.", HttpStatus.SC_OK, credentialResponse.getStatus());
|
||||
assertNotNull("A credential should be responded.", credentialResponse.getEntity());
|
||||
CredentialResponse credentialResponseVO = JsonSerialization.mapper.convertValue(credentialResponse.getEntity(), CredentialResponse.class);
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialResponseVO.getCredential(), JsonWebToken.class).getToken();
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialResponseVO.getCredentials().get(0).getCredential(), JsonWebToken.class).getToken();
|
||||
|
||||
assertNotNull("A valid credential string should have been responded", jsonWebToken);
|
||||
assertNotNull("The credentials should be included at the vc-claim.", jsonWebToken.getOtherClaims().get("vc"));
|
||||
@ -442,7 +442,7 @@ public class OID4VCJWTIssuerEndpointTest extends OID4VCIssuerEndpointTest {
|
||||
assertEquals(200, response.getStatus());
|
||||
CredentialResponse credentialResponse = JsonSerialization.readValue(response.readEntity(String.class), CredentialResponse.class);
|
||||
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialResponse.getCredential(), JsonWebToken.class).getToken();
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create((String) credentialResponse.getCredentials().get(0).getCredential(), JsonWebToken.class).getToken();
|
||||
assertEquals("did:web:test.org", jsonWebToken.getIssuer());
|
||||
|
||||
VerifiableCredential credential = JsonSerialization.mapper.convertValue(jsonWebToken.getOtherClaims().get("vc"), VerifiableCredential.class);
|
||||
|
||||
@ -233,7 +233,8 @@ public class OID4VCSdJwtIssuingEndpointTest extends OID4VCIssuerEndpointTest {
|
||||
CredentialResponse credentialResponseVO = JsonSerialization.mapper.convertValue(credentialResponse.getEntity(), CredentialResponse.class);
|
||||
new TestCredentialResponseHandler(vct).handleCredentialResponse(credentialResponseVO);
|
||||
|
||||
return SdJwtVP.of(credentialResponseVO.getCredential().toString());
|
||||
// Get the credential from the credentials array
|
||||
return SdJwtVP.of(credentialResponseVO.getCredentials().get(0).getCredential().toString());
|
||||
}
|
||||
|
||||
// Tests the complete flow from
|
||||
@ -445,7 +446,7 @@ public class OID4VCSdJwtIssuingEndpointTest extends OID4VCIssuerEndpointTest {
|
||||
@Override
|
||||
protected void handleCredentialResponse(CredentialResponse credentialResponse) throws VerificationException {
|
||||
// SDJWT have a special format.
|
||||
SdJwtVP sdJwtVP = SdJwtVP.of(credentialResponse.getCredential().toString());
|
||||
SdJwtVP sdJwtVP = SdJwtVP.of(credentialResponse.getCredentials().get(0).getCredential().toString());
|
||||
JsonWebToken jsonWebToken = TokenVerifier.create(sdJwtVP.getIssuerSignedJWT().toJws(), JsonWebToken.class).getToken();
|
||||
|
||||
assertNotNull("A valid credential string should have been responded", jsonWebToken);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user