Skip to content

Commit

Permalink
[ES-1063] added new API for exchange of verified claims.
Browse files Browse the repository at this point in the history
Signed-off-by: Mahammed Taheer <[email protected]>
  • Loading branch information
mahammedtaheer committed Jan 22, 2025
1 parent 5dae575 commit c4487d4
Show file tree
Hide file tree
Showing 16 changed files with 607 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ public int updateBindingCertificateForSameToken(@Param("tokenId") String tokenId
@Param("certData") String certificateData,
@Param("certThumbprint") String certThumbprint,
@Param("notAfterDate") LocalDateTime notAfterDate);

@Query("SELECT i.token, i.idVidHash FROM IdentityBindingCertificateStore i where i.publicKeyHash = :publicKeyHash")
List<Object[]> findIdentityBindingDataByPublicKeys(@Param("publicKeyHash") String publicKeyHash);
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public enum AuditEvents {

KYC_REQUEST_RESPONSE_V2("IDA_019", "System", "Kyc Auth V2 Request"),

KYC_EXCHANGE_REQUEST_RESPONSE_V2("IDA_020", "System", "Kyc Exchange V2 Request"),

/** Static_Pin_Storage_Request_Response. */
STATIC_PIN_STORAGE_REQUEST_RESPONSE("IDA-EVT-OLD-006","BUSINESS", ""),//not applicable for release v1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public enum AuditModules {
KYC_AUTH_V2("IDA-KAT-V2", "KYC Authentication Request for V2", "KYC Authenticator V2"),

KYC_EXCHANGE("IDA-KEX", "KYC Exchange Request", "KYC Exchange"),

KYC_EXCHANGE_V2("IDA-KEX-V2", "KYC Exchange Request for V2", "KYC Exchange V2"),

VCI_EXCHANGE("IDA-VCI", "VCI Exchange Request", "VCI Exchange"),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,17 @@ public final class IdAuthCommonConstants {

public static final String COMMA_STRING = ",";

public static final String CLAIMS = "claims";

public static final String VERIFICATION = "verification";

public static final String TRUST_FRAMEWORK = "trust_framework";

public static final String VERIFICATION_VALUE = "value";

public static final String VERIFICATION_VALUES = "values";

public static final String VERIFIED_CLAIMS = "verified_claims";

private IdAuthCommonConstants() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ public enum IdAuthenticationErrorConstants {
KYC_TOKEN_INVALID_TRANSACTION_ID("IDA-KYE-005", "KYC Auth and KYC Exchange transaction ids are different."),
PARTNER_POLICY_NOT_FOUND("IDA-KYE-006", "Partner Policy not found."),
KYC_TOKEN_INVALID_UIN_VID("IDA-KYE-007", "KYC Token does not belong to the input UIN/VID."),
DUPLICATE_CLAIMS_FOUND("IDA-KYE-008", "Duplicate claims found in request."),

ID_KEY_BINDING_NOT_ALLOWED("IDA-IKB-001", "Key Binding not allowed for the Id."),
CREATE_PUBLIC_KEY_OBJECT_ERROR("IDA-IKB-002", "Error creating Public Key object."),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package io.mosip.authentication.core.indauth.dto;

import java.util.List;
import java.util.Map;

import javax.validation.constraints.NotNull;

import io.mosip.authentication.core.dto.ObjectWithMetadata;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* The class KycExchangeRequestDTOV2 to holds the request parameters
* for Kyc Exchange Request Object for OIDC4IDA.
*
* @author Mahammed Taheer
*
*/

@Data
@EqualsAndHashCode(callSuper=true)
public class KycExchangeRequestDTOV2 extends BaseRequestDTO implements ObjectWithMetadata {

/** The Variable to hold value of kyc Token */
@NotNull
private String kycToken;

/** The Variable to hold value of list of user selected locales */
private List<String> locales;

private Map<String, Object> metadata;

/*
* Support for OIDC4IDA claims.
* one "verification", and "claims".
* Eg:
*
"verified_claims":{
"verification":{
"trust_framework":{
"value":"abd" or
"values": ["tf1", "tf2"]
},
"time":{
"max_age":"1933"
}
},
"claims":{ // Verified Claims
"given_name":null,
"family_name":null,
"birthdate":null
}
}
* Support for multiple objects contains array of "verification" and "claims".
*
* Eg:
*
"verified_claims":[
{
"verification":{
"trust_framework":{
"value":"abd" or
"values": ["tf1", "tf2"]
},
"time":{
"max_age":"1933"
}
},
"claims":{ // Verified Claims
"given_name":null,
"family_name":null
}
},
{
"verification":{
"trust_framework":{
"value":"xyz" or
"values": ["tf3", "tf4"]
},
"time":{
"max_age":"1933"
}
},
"claims":{ // Verified Claims
"birthdate":null
}
}
]
*
*/
List<Map<String, Object>> verifiedClaims;

/*
* User consented unverified claims list.
*/
Map<String, Object> unVerifiedConsentedClaims;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.mosip.authentication.core.indauth.dto.KycAuthResponseDTO;
import io.mosip.authentication.core.indauth.dto.KycAuthResponseDTOV2;
import io.mosip.authentication.core.indauth.dto.KycExchangeRequestDTO;
import io.mosip.authentication.core.indauth.dto.KycExchangeRequestDTOV2;
import io.mosip.authentication.core.indauth.dto.KycExchangeResponseDTO;

/**
Expand Down Expand Up @@ -97,7 +98,7 @@ KycExchangeResponseDTO processKycExchange(KycExchangeRequestDTO kycExchangeReque
String partnerId, String oidcClientId, Map<String, Object> metadata, ObjectWithMetadata requestWithMetadata) throws IdAuthenticationBusinessException;

/**
* Process the KycAuthRequestDTOV2 to integrate with KYCService.
* Process the KycAuthRequestDTOV2 to integrate with KYCService for OIDC4IDA.
*
* @param kycAuthRequestDtoV2 is DTO of KycAuthRequestDTOV2
* @param authResponseDTO the auth response DTO
Expand All @@ -108,4 +109,20 @@ KycExchangeResponseDTO processKycExchange(KycExchangeRequestDTO kycExchangeReque
*/
KycAuthResponseDTOV2 processKycAuthV2(@Nonnull AuthRequestDTO kycAuthRequestDtoV2, AuthResponseDTO authResponseDTO,
String partnerId, String oidcClientId, Map<String, Object> metadata) throws IdAuthenticationBusinessException;

/**
* Process the KycExchangeRequestDTOV2 to integrate with KYCService for OIDC4IDA.
*
* @param kycExchangeRequestDTOV2 is DTO of KycExchangeRequestDTOV2
* @param partnerId the partner id
* @param oidcClientId the client id
* @param metadata the metadata
* @param requestWithMetadata the request with metadata
* @return the kyc auth response DTO
* @throws IdAuthenticationBusinessException the id authentication business
* exception
*/
KycExchangeResponseDTO processKycExchangeV2(KycExchangeRequestDTOV2 kycExchangeRequestDTOV2,
String partnerId, String oidcClientId, Map<String, Object> metadata, ObjectWithMetadata requestWithMetadata) throws IdAuthenticationBusinessException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public interface IdentityKeyBindingService {
* @throws IdAuthenticationBusinessException the id authentication business exception
*
*/
boolean isPublicKeyBinded(String idVid, Map<String, Object> publicKeyJWK) throws IdAuthenticationBusinessException;
boolean isPublicKeyBinded(String idVid, Map<String, Object> publicKeyJWK, String idvIdType) throws IdAuthenticationBusinessException;

/**
* Method used to create certificate for the input public key for key binding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.mosip.authentication.core.exception.IdAuthenticationBusinessException;
import io.mosip.authentication.core.indauth.dto.IdentityInfoDTO;
import io.mosip.authentication.core.indauth.dto.KycExchangeRequestDTO;
import io.mosip.authentication.core.indauth.dto.KycExchangeRequestDTOV2;
import io.mosip.authentication.core.indauth.dto.EKycResponseDTO;

/**
Expand Down Expand Up @@ -90,4 +91,22 @@ String buildKycExchangeResponse(String subject, Map<String, List<IdentityInfoDTO
* exception
*/
String buildVerifiedClaimsMetadata(String verifiedClaimsData, String oidcClientId) throws IdAuthenticationBusinessException;

/**
* Method to build kyc exchange version 2 verified claims data.
*
* @param subject Partner Specific token as subject for user claims
* @param idInfo List of Identity Info of the user.
* @param consentedAttributes Consented Attributes.
* @param locales selected locales.
* @param idVid individual Id
* @param kycExchangeRequestDTOV2 KycExchangeRequestDTOV2 object.
* @return String
* @throws IdAuthenticationBusinessException the id authentication business
* exception
*/
String buildExchangeVerifiedClaimsData(String subject, Map<String, List<IdentityInfoDTO>> idInfo,
List<String> unverifiedConsentClaims, List<String> verifiedConsentClaims,
List<String> locales, String idVid,
KycExchangeRequestDTOV2 kycExchangeRequestDTOV2 ) throws IdAuthenticationBusinessException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,71 @@ public KycAuthResponseDTOV2 processKycAuthV2(@Validated @RequestBody KycAuthRequ
throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS);
}
}

/**
* Controller Method for Kyc-exchange for version 2.
*
* @param kycExchangeRequestDTO the kyc exchange request DTO V2
* @param errors the errors
* @return KycExchangeResponseDTO the kyc exchange response DTO V2
* @throws IdAuthenticationBusinessException the id authentication business
* exception
* @throws IdAuthenticationAppException the id authentication app exception
* @throws IdAuthenticationDaoException the id authentication dao exception
*/
@PostMapping(path = "/kyc-exchange/v2/delegated/{IdP-LK}/{Auth-Partner-ID}/{OIDC-Client-Id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Kyc Exchange Request", description = "Kyc Exchange Request", tags = { "kyc-auth-controller" })
@SecurityRequirement(name = "Authorization")
@Parameter(in = ParameterIn.HEADER, name = "signature")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Request authenticated successfully",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = IdAuthenticationAppException.class)))),
@ApiResponse(responseCode = "201", description = "Created" ,content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "401", description = "Unauthorized" ,content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "403", description = "Forbidden" ,content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "404", description = "Not Found" ,content = @Content(schema = @Schema(hidden = true)))})
public KycExchangeResponseDTO processKycExchangeV2(@Validated @RequestBody KycExchangeRequestDTOV2 kycExchangeRequestDTOV2,
@ApiIgnore Errors errors, @PathVariable("IdP-LK") String mispLK, @PathVariable("Auth-Partner-ID") String partnerId,
@PathVariable("OIDC-Client-Id") String oidcClientId, HttpServletRequest request)
throws IdAuthenticationBusinessException, IdAuthenticationAppException, IdAuthenticationDaoException {
if(request instanceof ObjectWithMetadata) {
ObjectWithMetadata requestWithMetadata = (ObjectWithMetadata) request;
Optional<PartnerDTO> partner = partnerService.getPartner(partnerId, kycExchangeRequestDTOV2.getMetadata());
AuthTransactionBuilder authTxnBuilder = authTransactionHelper
.createAndSetAuthTxnBuilderMetadataToRequest(kycExchangeRequestDTOV2, false, partner);
try {

String idType = Objects.nonNull(kycExchangeRequestDTOV2.getIndividualIdType()) ? kycExchangeRequestDTOV2.getIndividualIdType()
: idTypeUtil.getIdType(kycExchangeRequestDTOV2.getIndividualId()).getType();
kycExchangeRequestDTOV2.setIndividualIdType(idType);
kycExchangeValidator.validateIdvId(kycExchangeRequestDTOV2.getIndividualId(), idType, errors);
DataValidationUtil.validate(errors);

Map<String, Object> metadata = kycExchangeRequestDTOV2.getMetadata();
KycExchangeResponseDTO kycExchangeResponseDTO = kycFacade.processKycExchangeV2(kycExchangeRequestDTOV2,
partnerId, oidcClientId, metadata, requestWithMetadata);

return kycExchangeResponseDTO;
} catch (IDDataValidationException e) {
mosipLogger.error(IdAuthCommonConstants.SESSION_ID, this.getClass().getSimpleName(), "processKycExchange",
e.getErrorTexts().isEmpty() ? "" : e.getErrorText());
IdaRequestResponsConsumerUtil.setIdVersionToObjectWithMetadata(requestWithMetadata, e);
if(kycExchangeRequestDTOV2.getTransactionID() == null)
kycExchangeRequestDTOV2.setTransactionID(IdAuthCommonConstants.NO_TRANSACTION_ID);
e.putMetadata(IdAuthCommonConstants.TRANSACTION_ID, kycExchangeRequestDTOV2.getTransactionID());
throw authTransactionHelper.createDataValidationException(authTxnBuilder, e, requestWithMetadata);
} catch (IdAuthenticationBusinessException e) {
mosipLogger.error(IdAuthCommonConstants.SESSION_ID, this.getClass().getSimpleName(), "processKycExchange",
e.getErrorTexts().isEmpty() ? "" : e.getErrorText());
authTransactionHelper.setAuthTransactionEntityMetadata(e, authTxnBuilder, requestWithMetadata);
authTransactionHelper.setAuthTransactionEntityMetadata(requestWithMetadata, authTxnBuilder);
IdaRequestResponsConsumerUtil.setIdVersionToObjectWithMetadata(requestWithMetadata, e);
e.putMetadata(IdAuthCommonConstants.TRANSACTION_ID, kycExchangeRequestDTOV2.getTransactionID());
throw new IdAuthenticationAppException(e.getErrorCode(), e.getErrorText(), e);
}
} else {
mosipLogger.error("Technical error. HttpServletRequest is not instanceof ObjectWithMetada.");
throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ public AuthResponseDTO authenticateIndividual(AuthRequestDTO authRequest, String
idService.checkIdKeyBindingPermitted(idvid, idvIdType);

boolean keyBinded = keyBindingService.isPublicKeyBinded(idvid,
((IdentityKeyBindingRequestDTO) authRequest).getIdentityKeyBinding().getPublicKeyJWK());
((IdentityKeyBindingRequestDTO) authRequest).getIdentityKeyBinding().getPublicKeyJWK(),
idvIdType);
if (keyBinded) {
logger.error(IdAuthCommonConstants.SESSION_ID, this.getClass().getSimpleName(), "checkIdKeyBindingPermitted",
"Public key already binded to an VID.");
Expand Down
Loading

0 comments on commit c4487d4

Please sign in to comment.