diff --git a/authentication/esignet-integration-impl/pom.xml b/authentication/esignet-integration-impl/pom.xml
new file mode 100644
index 00000000000..e49686df59e
--- /dev/null
+++ b/authentication/esignet-integration-impl/pom.xml
@@ -0,0 +1,225 @@
+
+ 4.0.0
+
+
+ io.mosip.authentication
+ authentication-parent
+ 1.1.5.5-SNAPSHOT
+
+
+ esignet-integration-impl
+ esignet-integration-impl
+ e-Signet Integration Implementation Library
+
+
+ 11
+ 1.1.5
+ 1.1.5.3
+
+
+
+
+ junit
+ junit
+ 4.13.1
+ test
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.22
+ compile
+
+
+
+ io.mosip.esignet
+ esignet-integration-api
+ 1.0.0-SNAPSHOT
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+
+ io.mosip.kernel
+ kernel-keymanager-service
+ 1.2.1-SNAPSHOT
+ provided
+ lib
+
+
+ org.springframework.cloud
+ spring-cloud-starter-sleuth
+
+
+ org.springframework.security
+ spring-security-test
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-jdbc
+
+
+ org.springframework
+ spring-aop
+
+
+ org.springframework
+ spring-core
+
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${jackson.version}
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ 2.3.6.RELEASE
+
+
+ io.mosip.authentication
+ authentication-common
+ ${authentication-common.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ io.mosip.kernel
+ kernel-biosdk-provider
+
+
+ io.mosip.kernel
+ kernel-websubclient-api
+
+
+ io.mosip.idrepository
+ id-repository-core
+
+
+ io.mosip.kernel
+ kernel-dataaccess-hibernate
+
+
+ io.mosip.kernel
+ kernel-pinvalidator
+
+
+
+
+ io.mosip.biometric.util
+ biometrics-util
+ ${kernel-biometrics-util}
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ io.mosip.kernel
+ kernel-core
+ ${kernel-core.version}
+
+
+ org.springframework.boot
+
+ spring-boot-starter-security
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-jdbc
+
+
+ org.springframework
+ spring-aop
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ io.mosip.kernel
+ kernel-cbeffutil-api
+ ${kernel-cbeffutil-api.version}
+
+
+ io.mosip.kernel
+ kernel-core
+
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${maven.swagger.version}
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-aop
+
+
+ org.springframework
+ spring-core
+
+
+
+
+
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/config/IdaConfig.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/config/IdaConfig.java
new file mode 100644
index 00000000000..d648ec9c12e
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/config/IdaConfig.java
@@ -0,0 +1,140 @@
+package io.mosip.authentication.esignet.integration.config;
+
+import org.mockito.Mockito;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import io.mosip.authentication.common.service.cache.MasterDataCache;
+import io.mosip.authentication.common.service.config.IDAMappingConfig;
+import io.mosip.authentication.common.service.factory.RestRequestFactory;
+import io.mosip.authentication.common.service.helper.IdInfoHelper;
+import io.mosip.authentication.common.service.helper.RestHelper;
+import io.mosip.authentication.common.service.impl.IdInfoFetcherImpl;
+import io.mosip.authentication.common.service.integration.MasterDataManager;
+import io.mosip.authentication.common.service.integration.OTPManager;
+import io.mosip.authentication.common.service.integration.TokenIdManager;
+import io.mosip.authentication.common.service.repository.OtpTxnRepository;
+import io.mosip.authentication.common.service.repository.UinHashSaltRepo;
+import io.mosip.authentication.common.service.transaction.manager.IdAuthSecurityManager;
+import io.mosip.authentication.core.exception.IdAuthenticationBusinessException;
+import io.mosip.authentication.core.spi.demoauth.DemoNormalizer;
+import io.mosip.authentication.core.spi.indauth.match.IdInfoFetcher;
+import io.mosip.authentication.core.spi.notification.service.NotificationService;
+import io.mosip.kernel.cbeffutil.impl.CbeffImpl;
+import io.mosip.kernel.core.cbeffutil.spi.CbeffUtil;
+import io.mosip.kernel.cryptomanager.service.CryptomanagerService;
+import io.mosip.kernel.cryptomanager.service.impl.CryptomanagerServiceImpl;
+import io.mosip.kernel.tokenidgenerator.generator.TokenIDGenerator;
+import io.mosip.kernel.tokenidgenerator.service.TokenIDGeneratorService;
+import io.mosip.kernel.tokenidgenerator.service.impl.TokenIDGeneratorServiceImpl;
+import io.mosip.kernel.zkcryptoservice.service.spi.ZKCryptoManagerService;
+
+@EnableCaching
+@Configuration
+@Import(value= {IDAMappingConfig.class})
+public class IdaConfig {
+
+ @Bean
+ public TokenIDGeneratorService getTokenIdGeneratorService() {
+ return new TokenIDGeneratorServiceImpl();
+ }
+
+ @Bean
+ public TokenIdManager getTokenIdManager() {
+ return new TokenIdManager();
+ }
+
+ @Bean
+ public TokenIDGenerator getTokenIdGenerator() {
+ return new TokenIDGenerator();
+ }
+
+ @Bean
+ public IdInfoHelper getIdInfoHelper() {
+ return new IdInfoHelper();
+ }
+
+ @Bean
+ public IdInfoFetcher getIdInfoFetcher() {
+ return new IdInfoFetcherImpl();
+ }
+
+ @Bean
+ public OTPManager getOTPManager() {
+ return new OTPManager();
+ }
+
+ @Bean
+ public CryptomanagerService getCryptomanagerService() {
+ return new CryptomanagerServiceImpl();
+ }
+
+ @Bean("external")
+ public RestHelper getRestHelper() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(RestHelper.class);
+ }
+
+ @Bean
+ public NotificationService getNotificationService() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(NotificationService.class);
+ }
+
+ @Bean
+ public UinHashSaltRepo getUinHashSaltRepo() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(UinHashSaltRepo.class);
+ }
+
+ @Bean
+ public DemoNormalizer getDemoNormalizer() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(DemoNormalizer.class);
+ }
+
+ @Bean
+ public ZKCryptoManagerService getZKCryptoManagerService() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(ZKCryptoManagerService.class);
+ }
+
+ @Bean
+ public OtpTxnRepository getOtpTxnRepository() {
+ // Just using mock rest helper as it is not used here
+ return Mockito.mock(OtpTxnRepository.class);
+ }
+
+ @Bean
+ public CbeffUtil getCbeffUtil() {
+ return new CbeffImpl();
+ }
+
+ @Bean
+ public MasterDataManager getMasterDataManager() {
+ return new MasterDataManager();
+ }
+
+ @Bean
+ public MasterDataCache getMasterDataCache() {
+ return new MasterDataCache() {
+ @Override
+ public void loadMasterData() throws IdAuthenticationBusinessException {
+ //Do nothing
+ }
+ };
+ }
+
+ @Bean
+ public RestRequestFactory getRestRequestFactory() {
+ return new RestRequestFactory();
+ }
+
+ @Bean
+ public IdAuthSecurityManager getIdAuthSecurityManager() {
+ return new IdAuthSecurityManager();
+ }
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditRequest.java
new file mode 100644
index 00000000000..c4551c01068
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditRequest.java
@@ -0,0 +1,36 @@
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.time.LocalDateTime;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * The Class AuditRequestDto.
+ *
+ * @author Manoj SP
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class AuditRequest {
+
+ private String eventId;
+ private String eventName;
+ private String eventType;
+ private LocalDateTime actionTimeStamp;
+ private String hostName;
+ private String hostIp;
+ private String applicationId;
+ private String applicationName;
+ private String sessionUserId;
+ private String sessionUserName;
+ private String id;
+ private String idType;
+ private String createdBy;
+ private String moduleName;
+ private String moduleId;
+ private String description;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditResponse.java
new file mode 100644
index 00000000000..1dcc2a4e1ae
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/AuditResponse.java
@@ -0,0 +1,10 @@
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class AuditResponse {
+
+ private boolean status;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/ClientIdSecretKeyRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/ClientIdSecretKeyRequest.java
new file mode 100644
index 00000000000..e93ec34b89d
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/ClientIdSecretKeyRequest.java
@@ -0,0 +1,21 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ClientIdSecretKeyRequest {
+
+ private String clientId;
+ private String secretKey;
+ private String appId;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/Error.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/Error.java
new file mode 100644
index 00000000000..04c490a42f8
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/Error.java
@@ -0,0 +1,20 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Error {
+
+ private String errorCode;
+ private String errorMessage;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/GetAllCertificatesResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/GetAllCertificatesResponse.java
new file mode 100644
index 00000000000..94a3dc03770
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/GetAllCertificatesResponse.java
@@ -0,0 +1,18 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+
+import io.mosip.esignet.api.dto.KycSigningCertificateData;
+import lombok.Data;
+
+@Data
+public class GetAllCertificatesResponse {
+
+ private List allCertificates;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaError.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaError.java
new file mode 100644
index 00000000000..e967bb5e22e
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaError.java
@@ -0,0 +1,16 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class IdaError {
+
+ private String actionMessage;
+ private String errorCode;
+ private String errorMessage;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycAuthRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycAuthRequest.java
new file mode 100644
index 00000000000..c6b32275a71
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycAuthRequest.java
@@ -0,0 +1,53 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+import java.util.Map;
+
+import lombok.Data;
+
+@Data
+public class IdaKycAuthRequest {
+
+ private String id;
+ private String version;
+ private String individualId;
+ private String individualIdType;
+ private String transactionID;
+ private String requestTime;
+ private String specVersion;
+ private String thumbprint;
+ private String domainUri;
+ private String env;
+ private boolean consentObtained;
+ private String request;
+ private String requestHMAC;
+ private String requestSessionKey;
+ private Map metadata;
+ private List allowedKycAttributes;
+ private Map requestedAuth;
+
+ @Data
+ public static class AuthRequest {
+ private String otp;
+ private String staticPin;
+ private String timestamp;
+ private List biometrics;
+ private List keyBindedTokens;
+ }
+
+ @Data
+ public static class Biometric {
+ private String data;
+ private String hash;
+ private String sessionKey;
+ private String specVersion;
+ private String thumbprint;
+ }
+
+
+}
\ No newline at end of file
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeRequest.java
new file mode 100644
index 00000000000..78a6d123e29
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeRequest.java
@@ -0,0 +1,24 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+public class IdaKycExchangeRequest {
+
+ private String id;
+ private String version;
+ private String requestTime;
+ private String transactionID;
+ private String kycToken;
+ private List consentObtained;
+ private List locales;
+ private String respType;
+ private String individualId;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeResponse.java
new file mode 100644
index 00000000000..01da00c1de1
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycExchangeResponse.java
@@ -0,0 +1,14 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class IdaKycExchangeResponse {
+
+ private String encryptedKyc;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycResponse.java
new file mode 100644
index 00000000000..484439e1cfd
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaKycResponse.java
@@ -0,0 +1,28 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class IdaKycResponse {
+
+ /** The Variable to hold value of kyc Status */
+ private boolean kycStatus;
+
+ /** The Variable to hold value of kyc Status */
+ private boolean authStatus;
+
+ /** The Variable to hold value of auth Token */
+ private String authToken;
+
+ private String thumbprint;
+
+ private String sessionKey;
+
+ /** The Variable to hold value of identity */
+ private String identity;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaOtpResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaOtpResponse.java
new file mode 100644
index 00000000000..4d923a203de
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaOtpResponse.java
@@ -0,0 +1,14 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class IdaOtpResponse {
+ private String maskedEmail;
+ private String maskedMobile;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaResponseWrapper.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaResponseWrapper.java
new file mode 100644
index 00000000000..f9ee146f622
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaResponseWrapper.java
@@ -0,0 +1,22 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+public class IdaResponseWrapper {
+
+ private String id;
+ private String version;
+ private String transactionID;
+ private String responseTime;
+ private T response;
+ private List errors;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpRequest.java
new file mode 100644
index 00000000000..358cf0d6ae3
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpRequest.java
@@ -0,0 +1,23 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+public class IdaSendOtpRequest {
+
+ private String id;
+ private String version;
+ private String individualId;
+ private String individualIdType;
+ private String transactionID;
+ private String requestTime;
+ private List otpChannel;
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpResponse.java
new file mode 100644
index 00000000000..c1ccb48ac65
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/IdaSendOtpResponse.java
@@ -0,0 +1,22 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+public class IdaSendOtpResponse {
+
+ private String id;
+ private String version;
+ private String transactionID;
+ private String responseTime;
+ private List errors;
+ private IdaOtpResponse response;
+}
+
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindedToken.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindedToken.java
new file mode 100644
index 00000000000..dbe00127abb
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindedToken.java
@@ -0,0 +1,12 @@
+package io.mosip.authentication.esignet.integration.dto;
+
+
+import lombok.Data;
+
+@Data
+public class KeyBindedToken {
+
+ private String token;
+ private String type;
+ private String format;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingRequest.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingRequest.java
new file mode 100644
index 00000000000..214a0b6708c
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingRequest.java
@@ -0,0 +1,22 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class KeyBindingRequest extends IdaKycAuthRequest {
+
+ private IdentityKeyBinding identityKeyBinding;
+
+ @Data
+ public static class IdentityKeyBinding {
+ private Map publicKeyJWK;
+ private String authFactorType;
+ }
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingResponse.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingResponse.java
new file mode 100644
index 00000000000..e223bd3c019
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/dto/KeyBindingResponse.java
@@ -0,0 +1,16 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.dto;
+
+import lombok.Data;
+
+@Data
+public class KeyBindingResponse {
+
+ private String identityCertificate;
+ private String authToken;
+ private boolean bindingAuthStatus;
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/AuthTransactionHelper.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/AuthTransactionHelper.java
new file mode 100644
index 00000000000..6a1873abb92
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/AuthTransactionHelper.java
@@ -0,0 +1,79 @@
+package io.mosip.authentication.esignet.integration.helper;
+
+import java.time.LocalDateTime;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.mosip.authentication.esignet.integration.dto.ClientIdSecretKeyRequest;
+import io.mosip.kernel.core.http.RequestWrapper;
+import io.mosip.kernel.core.http.ResponseWrapper;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+public class AuthTransactionHelper {
+
+ private static final String AUTH_TOKEN_CACHE = "authtokens";
+
+ public static final String AUTH_TOKEN_CACHE_KEY = "auth_token";
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Value("${mosip.esignet.authenticator.ida.auth-token-url}")
+ private String authTokenUrl;
+
+ @Value("${mosip.esignet.authenticator.ida.client-id}")
+ private String clientId;
+
+ @Value("${mosip.esignet.authenticator.ida.secret-key}")
+ private String secretKey;
+
+ @Value("${mosip.esignet.authenticator.ida.app-id}")
+ private String appId;
+
+ @Cacheable(value = AUTH_TOKEN_CACHE, key = "#root.target.AUTH_TOKEN_CACHE_KEY")
+ public String getAuthToken() throws Exception {
+ log.info("Started to get auth-token with appId : {} && clientId : {}",
+ appId, clientId);
+
+
+
+ RequestWrapper authRequest = new RequestWrapper<>();
+ authRequest.setRequesttime(LocalDateTime.now());
+ ClientIdSecretKeyRequest clientIdSecretKeyRequest = new ClientIdSecretKeyRequest(clientId, secretKey, appId);
+ authRequest.setRequest(clientIdSecretKeyRequest);
+
+ String requestBody = objectMapper.writeValueAsString(authRequest);
+ RequestEntity requestEntity = RequestEntity
+ .post(UriComponentsBuilder.fromUriString(authTokenUrl).build().toUri())
+ .contentType(MediaType.APPLICATION_JSON)
+ .body(requestBody);
+ ResponseEntity responseEntity = restTemplate.exchange(requestEntity,
+ new ParameterizedTypeReference() {});
+
+ String authToken = responseEntity.getHeaders().getFirst("authorization");
+ return authToken;
+ }
+
+ @CacheEvict(value = AUTH_TOKEN_CACHE, allEntries = true)
+ public void purgeAuthTokenCache() {
+ log.info("Evicting entry from AUTH_TOKEN_CACHE");
+ }
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataCache.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataCache.java
new file mode 100644
index 00000000000..01a0370d3d9
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataCache.java
@@ -0,0 +1,33 @@
+package io.mosip.authentication.esignet.integration.helper;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.Cache;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @author Loganathan S
+ *
+ */
+@Component
+public class IdentityDataCache {
+
+ private static final String ENCRYPTED_IDENTITY_DATA = "encryptedIdentityData";
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ public void storeToCache(String key, T data) {
+ Cache dataCache = cacheManager.getCache(ENCRYPTED_IDENTITY_DATA);
+ dataCache.put(key, data);
+ }
+
+ public T retrieveFromCache(String key, Class clazz) {
+ Cache dataCache = cacheManager.getCache(ENCRYPTED_IDENTITY_DATA);
+ return dataCache.get(key, clazz);
+ }
+
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataStore.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataStore.java
new file mode 100644
index 00000000000..919aa99f09e
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/helper/IdentityDataStore.java
@@ -0,0 +1,28 @@
+package io.mosip.authentication.esignet.integration.helper;
+
+import java.util.Objects;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+/**
+ *
+ * @author Loganathan S
+ *
+ */
+@Component
+public class IdentityDataStore {
+
+ @Autowired
+ private IdentityDataCache identityDataCache;
+
+ public void putEncryptedIdentityData(String kycToken, String psut, String encryptedIdentityData) {
+ Objects.requireNonNull(encryptedIdentityData);
+ identityDataCache.storeToCache(kycToken + psut, encryptedIdentityData);
+ }
+
+ public String getEncryptedIdentityData(String kycToken, String psut) {
+ return identityDataCache.retrieveFromCache(kycToken + psut, String.class);
+ }
+
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/HelperService.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/HelperService.java
new file mode 100644
index 00000000000..a948732c71f
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/HelperService.java
@@ -0,0 +1,306 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.service;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.NotImplementedException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.mosip.authentication.esignet.integration.dto.IdaKycAuthRequest;
+import io.mosip.authentication.esignet.integration.dto.IdaKycAuthRequest.AuthRequest;
+import io.mosip.authentication.esignet.integration.dto.IdaSendOtpRequest;
+import io.mosip.authentication.esignet.integration.dto.IdaSendOtpResponse;
+import io.mosip.authentication.esignet.integration.dto.KeyBindedToken;
+import io.mosip.esignet.api.dto.AuthChallenge;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.KycAuthException;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.kernel.core.util.DateUtils;
+import io.mosip.kernel.core.util.HMACUtils2;
+import io.mosip.kernel.crypto.jce.core.CryptoCore;
+import io.mosip.kernel.cryptomanager.dto.CryptomanagerRequestDto;
+import io.mosip.kernel.cryptomanager.dto.CryptomanagerResponseDto;
+import io.mosip.kernel.cryptomanager.service.CryptomanagerService;
+import io.mosip.kernel.keygenerator.bouncycastle.util.KeyGeneratorUtils;
+import io.mosip.kernel.keymanagerservice.util.KeymanagerUtil;
+import io.mosip.kernel.partnercertservice.util.PartnerCertificateManagerUtil;
+import io.mosip.kernel.signature.dto.JWTSignatureRequestDto;
+import io.mosip.kernel.signature.dto.JWTSignatureResponseDto;
+import io.mosip.kernel.signature.service.SignatureService;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@Slf4j
+public class HelperService {
+
+ public static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ public static final String SIGNATURE_HEADER_NAME = "signature";
+ public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
+ public static final String UTC_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
+ public static final String INVALID_PARTNER_CERTIFICATE = "invalid_partner_cert";
+ public static final String OIDC_PARTNER_APP_ID = "OIDC_PARTNER";
+ public static final String BINDING_TRANSACTION = "bindingtransaction";
+ private static Base64.Encoder urlSafeEncoder;
+ private static Base64.Decoder urlSafeDecoder;
+
+ static {
+ urlSafeEncoder = Base64.getUrlEncoder().withoutPadding();
+ urlSafeDecoder = Base64.getUrlDecoder();
+ }
+
+ @Value("${mosip.esignet.authenticator.ida-send-otp-id:mosip.identity.otp}")
+ private String sendOtpId;
+
+ @Value("${mosip.esignet.authenticator.ida-send-otp-version:1.0}")
+ private String idaVersion;
+
+ @Value("${mosip.esignet.authenticator.ida.cert-url}")
+ private String idaPartnerCertificateUrl;
+
+ @Value("${mosip.esignet.authenticator.ida.send-otp-url}")
+ private String sendOtpUrl;
+
+ @Value("${mosip.kernel.keygenerator.symmetric-algorithm-name}")
+ private String symmetricAlgorithm;
+
+ @Value("${mosip.kernel.keygenerator.symmetric-key-length}")
+ private int symmetricKeyLength;
+
+ @Autowired
+ private KeymanagerUtil keymanagerUtil;
+
+ @Autowired
+ private SignatureService signatureService;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private CryptoCore cryptoCore;
+
+ private Certificate idaPartnerCertificate;
+
+ @Autowired
+ private CryptomanagerService cryptomanagerService;
+
+
+ @Cacheable(value = BINDING_TRANSACTION, key = "#idHash")
+ public String getTransactionId(String idHash) {
+ return HelperService.generateTransactionId(10);
+ }
+
+ protected void setAuthRequest(List challengeList, IdaKycAuthRequest idaKycAuthRequest) throws Exception {
+ IdaKycAuthRequest.AuthRequest authRequest = new IdaKycAuthRequest.AuthRequest();
+ authRequest.setTimestamp(HelperService.getUTCDateTime());
+ challengeList.stream()
+ .filter( auth -> auth != null && auth.getAuthFactorType() != null)
+ .forEach( auth -> { buildAuthRequest(auth, authRequest, idaKycAuthRequest); });
+
+ KeyGenerator keyGenerator = KeyGeneratorUtils.getKeyGenerator(symmetricAlgorithm, symmetricKeyLength);
+ final SecretKey symmetricKey = keyGenerator.generateKey();
+ String request = objectMapper.writeValueAsString(authRequest);
+ String hexEncodedHash = HMACUtils2.digestAsPlainText(request.getBytes(StandardCharsets.UTF_8));
+ idaKycAuthRequest.setRequest(HelperService.b64Encode(cryptoCore.symmetricEncrypt(symmetricKey,
+ request.getBytes(StandardCharsets.UTF_8), null)));
+ idaKycAuthRequest.setRequestHMAC(HelperService.b64Encode(cryptoCore.symmetricEncrypt(symmetricKey,
+ hexEncodedHash.getBytes(StandardCharsets.UTF_8), null)));
+ Certificate certificate = getIdaPartnerCertificate();
+ idaKycAuthRequest.setThumbprint(HelperService.b64Encode(getCertificateThumbprint(certificate)));
+ log.info("IDA certificate thumbprint {}", idaKycAuthRequest.getThumbprint());
+ idaKycAuthRequest.setRequestSessionKey(HelperService.b64Encode(
+ cryptoCore.asymmetricEncrypt(certificate.getPublicKey(), symmetricKey.getEncoded())));
+ }
+
+
+ protected SendOtpResult sendOTP(String partnerId, String clientId, IdaSendOtpRequest idaSendOtpRequest)
+ throws SendOtpException, JsonProcessingException {
+ idaSendOtpRequest.setId(sendOtpId);
+ idaSendOtpRequest.setVersion(idaVersion);
+ idaSendOtpRequest.setRequestTime(getUTCDateTime());
+
+ //set signature header, body and invoke kyc exchange endpoint
+ String requestBody = objectMapper.writeValueAsString(idaSendOtpRequest);
+ RequestEntity requestEntity = RequestEntity
+ .post(UriComponentsBuilder.fromUriString(sendOtpUrl).pathSegment(partnerId, clientId).build().toUri())
+ .contentType(MediaType.APPLICATION_JSON_UTF8)
+ .header(SIGNATURE_HEADER_NAME, getRequestSignature(requestBody))
+ .header(AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_NAME)
+ .body(requestBody);
+ ResponseEntity responseEntity = restTemplate.exchange(requestEntity, IdaSendOtpResponse.class);
+ if(responseEntity.getStatusCode().is2xxSuccessful() && responseEntity.getBody() != null) {
+ IdaSendOtpResponse idaSendOtpResponse = responseEntity.getBody();
+ if(idaSendOtpRequest.getTransactionID().equals(idaSendOtpResponse.getTransactionID()) && idaSendOtpResponse.getResponse() != null){
+ return new SendOtpResult(idaSendOtpResponse.getTransactionID(),
+ idaSendOtpResponse.getResponse().getMaskedEmail(),
+ idaSendOtpResponse.getResponse().getMaskedMobile());
+ }
+ log.error("Errors in response received from IDA send-otp : {}", idaSendOtpResponse.getErrors());
+ throw new SendOtpException(idaSendOtpResponse.getErrors().get(0).getErrorCode());
+ }
+ log.error("Error response received from IDA (send-otp) with status : {}", responseEntity.getStatusCode());
+ throw new SendOtpException();
+ }
+
+ protected String getRequestSignature(String request) {
+ JWTSignatureRequestDto jwtSignatureRequestDto = new JWTSignatureRequestDto();
+ jwtSignatureRequestDto.setApplicationId(OIDC_PARTNER_APP_ID);
+ jwtSignatureRequestDto.setReferenceId("");
+ jwtSignatureRequestDto.setIncludePayload(false);
+ jwtSignatureRequestDto.setIncludeCertificate(true);
+ jwtSignatureRequestDto.setDataToSign(HelperService.b64Encode(request));
+ JWTSignatureResponseDto responseDto = signatureService.jwtSign(jwtSignatureRequestDto);
+ log.debug("Request signature ---> {}", responseDto.getJwtSignedData());
+ return responseDto.getJwtSignedData();
+ }
+
+ public String decrptData(String identityStr) {
+ CryptomanagerRequestDto cryptomanagerRequestDto = new CryptomanagerRequestDto();
+ cryptomanagerRequestDto.setApplicationId(OIDC_PARTNER_APP_ID);
+ cryptomanagerRequestDto.setData(identityStr);
+ cryptomanagerRequestDto.setTimeStamp(DateUtils.getUTCCurrentDateTime());
+ CryptomanagerResponseDto cryptomanagerResponseDto = cryptomanagerService.decrypt(cryptomanagerRequestDto);
+ return cryptomanagerResponseDto.getData();
+ }
+
+ protected Certificate getIdaPartnerCertificate() throws KycAuthException {
+ if(StringUtils.isEmpty(idaPartnerCertificate)) {
+ log.info("Fetching IDA partner certificate from : {}", idaPartnerCertificateUrl);
+ idaPartnerCertificate = keymanagerUtil.convertToCertificate(restTemplate.getForObject(idaPartnerCertificateUrl,
+ String.class));
+ }
+ if(PartnerCertificateManagerUtil.isCertificateDatesValid((X509Certificate)idaPartnerCertificate))
+ return idaPartnerCertificate;
+
+ log.info("PARTNER CERTIFICATE IS NOT VALID, Downloading the certificate again");
+ idaPartnerCertificate = keymanagerUtil.convertToCertificate(restTemplate.getForObject(idaPartnerCertificateUrl,
+ String.class));
+ if(PartnerCertificateManagerUtil.isCertificateDatesValid((X509Certificate)idaPartnerCertificate))
+ return idaPartnerCertificate;
+
+ throw new KycAuthException(INVALID_PARTNER_CERTIFICATE);
+ }
+
+ protected byte[] getCertificateThumbprint(Certificate certificate) {
+ try {
+ return DigestUtils.sha256(certificate.getEncoded());
+ } catch (CertificateEncodingException e) {
+ log.error("Failed to get cert thumbprint", e);
+ }
+ return new byte[]{};
+ }
+
+ /**
+ * Output format : 2022-12-01T03:22:46.720Z
+ * @return Formatted datetime
+ */
+ protected static String getUTCDateTime() {
+ return ZonedDateTime
+ .now(ZoneOffset.UTC)
+ .format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN));
+ }
+
+ protected static String b64Encode(byte[] bytes) {
+ return urlSafeEncoder.encodeToString(bytes);
+ }
+
+ protected static String b64Encode(String value) {
+ return urlSafeEncoder.encodeToString(value.getBytes(StandardCharsets.UTF_8));
+ }
+
+ protected static byte[] b64Decode(String value) {
+ return urlSafeDecoder.decode(value);
+ }
+
+ private void buildAuthRequest(AuthChallenge authChallenge, AuthRequest authRequest, IdaKycAuthRequest kycAauthRequest) {
+ log.info("Build kyc-auth request with authFactor : {}", authChallenge.getAuthFactorType());
+ switch (authChallenge.getAuthFactorType().toUpperCase()) {
+ case "OTP" :
+ authRequest.setOtp(authChallenge.getChallenge());
+ kycAauthRequest.getRequestedAuth().put("otp", true);
+ break;
+ case "PIN" :
+ authRequest.setStaticPin(authChallenge.getChallenge());
+ kycAauthRequest.getRequestedAuth().put("pin", true);
+ break;
+ case "BIO" :
+ kycAauthRequest.getRequestedAuth().put("bio", true);
+ byte[] decodedBio = HelperService.b64Decode(authChallenge.getChallenge());
+ try {
+ List biometrics = objectMapper.readValue(decodedBio,
+ new TypeReference>(){});
+ authRequest.setBiometrics(biometrics);
+ } catch (Exception e) {
+ log.error("Failed to parse biometric capture response", e);
+ }
+ break;
+ case "WLA" :
+ List list = new ArrayList<>();
+ KeyBindedToken keyBindedToken = new KeyBindedToken();
+ keyBindedToken.setType(authChallenge.getAuthFactorType());
+ keyBindedToken.setToken(authChallenge.getChallenge());
+ keyBindedToken.setFormat(authChallenge.getFormat());
+ list.add(keyBindedToken);
+ authRequest.setKeyBindedTokens(list);
+ break;
+ default:
+ throw new NotImplementedException("KYC auth not implemented");
+ }
+ }
+
+ protected static String generateTransactionId(int length) {
+ StringBuilder builder = new StringBuilder();
+ for(int i=0; i request = new RequestWrapper<>();
+
+ AuditRequest auditRequest = new AuditRequest();
+ auditRequest.setEventId(action.name());
+ auditRequest.setEventName(action.name());
+ auditRequest.setEventType(status.name());
+ auditRequest.setActionTimeStamp(DateUtils.getUTCCurrentDateTime());
+ auditRequest.setHostName("localhost");
+ auditRequest.setHostIp("localhost");
+ auditRequest.setApplicationId(ESIGNET);
+ auditRequest.setApplicationName(ESIGNET);
+ auditRequest.setSessionUserId(StringUtils.isEmpty(username)?"no-user":username);
+ auditRequest.setSessionUserName(StringUtils.isEmpty(username)?"no-user":username);
+ auditRequest.setIdType(TRANSACTION);
+ auditRequest.setCreatedBy(this.getClass().getSimpleName());
+ auditRequest.setModuleName(getModuleByAction(action));
+ auditRequest.setModuleId(getModuleByAction(action));
+ auditRequest.setDescription(getAuditDescription(audit));
+ auditRequest.setId(audit.getTransactionId());
+
+ request.setRequest(auditRequest);
+ request.setId("ida");
+ request.setRequesttime(DateUtils.getUTCCurrentDateTime());
+
+ String requestBody = objectMapper.writeValueAsString(request);
+ RequestEntity requestEntity = RequestEntity
+ .post(UriComponentsBuilder.fromUriString(auditManagerUrl).build().toUri())
+ .contentType(MediaType.APPLICATION_JSON).header(HttpHeaders.COOKIE, "Authorization=" + authToken)
+ .body(requestBody);
+ ResponseEntity responseEntity = restTemplate.exchange(requestEntity,
+ new ParameterizedTypeReference() {
+ });
+
+ if (responseEntity.getStatusCode().is2xxSuccessful() && responseEntity.getBody() != null) {
+ ResponseWrapper responseWrapper = responseEntity.getBody();
+ if (responseWrapper.getErrors() != null && !responseWrapper.getErrors().isEmpty()) {
+ log.error("Error response received from audit service with errors: {}",
+ responseWrapper.getErrors());
+ }
+ }
+
+ if(responseEntity.getStatusCode() == HttpStatus.FORBIDDEN ||
+ responseEntity.getStatusCode() == HttpStatus.UNAUTHORIZED) {
+ log.error("Audit call failed with error: {}, issue with auth-token hence purging the auth-token-cache",
+ responseEntity.getStatusCode());
+ authTransactionHelper.purgeAuthTokenCache();
+ }
+ } catch (Exception e) {
+ log.error("LogAudit failed with error : {}", e);
+ }
+ }
+
+ private String getAuditDescription(AuditDTO audit) throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("clientId", audit.getClientId());
+ json.put("relyingPartyId", audit.getRelyingPartyId());
+ json.put("state", audit.getState());
+ json.put("codeHash", audit.getCodeHash());
+ json.put("accessTokenHash", audit.getAccessTokenHash());
+ return json.toString();
+ }
+
+ private String getModuleByAction(Action action) {
+ switch (action) {
+ case OIDC_CLIENT_CREATE:
+ case OIDC_CLIENT_UPDATE:
+ return "ClientManagementController";
+ case GET_OAUTH_DETAILS:
+ case TRANSACTION_STARTED:
+ case SEND_OTP:
+ case AUTHENTICATE:
+ case GET_AUTH_CODE:
+ case DO_KYC_AUTH:
+ case DO_KYC_EXCHANGE:
+ return "AuthorizationController";
+ case GENERATE_TOKEN:
+ return "OAuthController";
+ case GET_USERINFO:
+ return "OpenIdConnectController";
+ case LINK_AUTH_CODE:
+ case LINK_AUTHENTICATE:
+ case LINK_CODE:
+ case LINK_SEND_OTP:
+ case LINK_STATUS:
+ case LINK_TRANSACTION:
+ case SAVE_CONSENT:
+ return "LinkedAuthorizationController";
+ case GET_CERTIFICATE:
+ case UPLOAD_CERTIFICATE:
+ return "SystemInfoController";
+ default:
+ return "EsignetService";
+ }
+ }
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImpl.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImpl.java
new file mode 100644
index 00000000000..8cfa549e7f6
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImpl.java
@@ -0,0 +1,667 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.service;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.mosip.authentication.common.service.helper.IdInfoHelper;
+import io.mosip.authentication.common.service.impl.match.BioMatchType;
+import io.mosip.authentication.common.service.integration.TokenIdManager;
+import io.mosip.authentication.core.constant.IdAuthConfigKeyConstants;
+import io.mosip.authentication.core.constant.IdAuthenticationErrorConstants;
+import io.mosip.authentication.core.exception.IdAuthenticationBusinessException;
+import io.mosip.authentication.core.indauth.dto.IdentityInfoDTO;
+import io.mosip.authentication.core.spi.bioauth.CbeffDocType;
+import io.mosip.authentication.core.spi.indauth.match.IdInfoFetcher;
+import io.mosip.authentication.esignet.integration.dto.GetAllCertificatesResponse;
+import io.mosip.authentication.esignet.integration.dto.IdaKycAuthRequest;
+import io.mosip.authentication.esignet.integration.dto.IdaKycExchangeResponse;
+import io.mosip.authentication.esignet.integration.dto.IdaKycResponse;
+import io.mosip.authentication.esignet.integration.dto.IdaResponseWrapper;
+import io.mosip.authentication.esignet.integration.dto.IdaSendOtpRequest;
+import io.mosip.authentication.esignet.integration.helper.AuthTransactionHelper;
+import io.mosip.authentication.esignet.integration.helper.IdentityDataStore;
+import io.mosip.biometrics.util.ConvertRequestDto;
+import io.mosip.biometrics.util.face.FaceDecoder;
+import io.mosip.esignet.api.dto.KycAuthDto;
+import io.mosip.esignet.api.dto.KycAuthResult;
+import io.mosip.esignet.api.dto.KycExchangeDto;
+import io.mosip.esignet.api.dto.KycExchangeResult;
+import io.mosip.esignet.api.dto.KycSigningCertificateData;
+import io.mosip.esignet.api.dto.SendOtpDto;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.KycAuthException;
+import io.mosip.esignet.api.exception.KycExchangeException;
+import io.mosip.esignet.api.exception.KycSigningCertificateException;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.esignet.api.spi.Authenticator;
+import io.mosip.esignet.api.util.ErrorConstants;
+import io.mosip.kernel.core.http.ResponseWrapper;
+import io.mosip.kernel.core.util.CryptoUtil;
+import io.mosip.kernel.signature.dto.JWTSignatureRequestDto;
+import io.mosip.kernel.signature.service.SignatureService;
+import lombok.extern.slf4j.Slf4j;
+import reactor.util.function.Tuple2;
+import reactor.util.function.Tuples;
+
+
+@ConditionalOnProperty(value = "mosip.esignet.integration.authenticator", havingValue = "IdaAuthenticatorImpl")
+@Component
+@Slf4j
+public class IdaAuthenticatorImpl implements Authenticator {
+
+ public static final String SIGNATURE_HEADER_NAME = "signature";
+ public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
+ public static final String KYC_EXCHANGE_TYPE = "oidc";
+ private static final String HASH_ALGORITHM_NAME = "SHA-256";
+ public static final String SUBJECT = "sub";
+ public static final String CLAIMS_LANG_SEPERATOR = "#";
+ public static final String ADDRESS_FORMATTED = "formatted";
+ public static final String FACE_ISO_NUMBER = "ISO19794_5_2011";
+ public static final String EMPTY = "";
+
+ @Value("${mosip.esignet.authenticator.ida-kyc-id:mosip.identity.kyc}")
+ private String kycId;
+
+ @Value("${mosip.esignet.authenticator.ida-authonly-id:mosip.identity.auth}")
+ private String authOnlyId;
+
+ @Value("${mosip.esignet.authenticator.ida-version:1.0}")
+ private String idaVersion;
+
+ @Value("${mosip.esignet.authenticator.ida-domainUri}")
+ private String idaDomainUri;
+
+ @Value("${mosip.esignet.authenticator.ida-env:Staging}")
+ private String idaEnv;
+
+ @Value("${mosip.esignet.authenticator.ida.kyc-url}")
+ private String kycUrl;
+
+ @Value("${mosip.esignet.authenticator.ida.auth-url}")
+ private String authUrl;
+
+ @Value("${mosip.esignet.authenticator.ida.otp-channels}")
+ private List otpChannels;
+
+ @Value("${mosip.esignet.authenticator.ida.get-certificates-url}")
+ private String getCertsUrl;
+
+ @Value("${mosip.esignet.authenticator.ida.application-id:IDA}")
+ private String applicationId;
+
+ @Value("${mosip.esignet.authenticator.ida.reference-id:SIGN}")
+ private String referenceId;
+
+ @Value("${mosip.esignet.authenticator.ida.client-id}")
+ private String clientId;
+
+ @Value("${mosip.esignet.authenticator.ida.wrapper.auth.partner.id}")
+ private String esignetAuthPartnerId;
+
+
+ @Value("${mosip.esignet.authenticator.ida.wrapper.auth.partner.apikey}")
+ private String esignetAuthPartnerApiKey;
+
+ @Value("${mosip.esignet.authenticator.ida.wrapper.auth.reference.id}")
+ private String esignetRefId;
+
+ @Value("${ida.idp.consented.picture.attribute.name:picture}")
+ private String consentedFaceAttributeName;
+
+ @Value("${ida.idp.consented.address.attribute.name:address}")
+ private String consentedAddressAttributeName;
+
+ @Value("${ida.idp.consented.individual_id.attribute.name:individual_id}")
+ private String consentedIndividualAttributeName;
+
+ @Value("${ida.idp.consented.picture.attribute.prefix:data:image/jpeg;base64,}")
+ private String consentedPictureAttributePrefix;
+
+ @Value("${mosip.ida.idp.consented.address.subset.attributes:}")
+ private String[] addressSubsetAttributes;
+
+ @Value("${ida.idp.consented.address.value.separator: }")
+ private String addressValueSeparator;
+
+ @Value("${ida.kyc.send-face-as-cbeff-xml:false}")
+ private boolean sendFaceAsCbeffXml;
+
+ @Value("${mosip.ida.kyc.exchange.sign.include.certificate:false}")
+ private boolean includeCertificate;
+
+ /** The sign applicationid. */
+ @Value("${mosip.ida.kyc.exchange.sign.applicationid:IDA_KYC_EXCHANGE}")
+ private String kycExchSignApplicationId;
+
+ /** The key splitter. */
+ @Value("${" + IdAuthConfigKeyConstants.KEY_SPLITTER + "}")
+ private String keySplitter;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Autowired
+ HelperService helperService;
+
+ @Autowired
+ private AuthTransactionHelper authTransactionHelper;
+
+ @Autowired
+ private IdentityDataStore identityDataStore;
+
+ @Autowired
+ private TokenIdManager tokenIdManager;
+
+ @Autowired
+ private IdInfoHelper idInfoHelper;
+
+ /** The token ID length. */
+ @Value("${mosip.ida.kyc.token.secret}")
+ private String kycTokenSecret;
+
+ @Autowired
+ private SignatureService signatureService;
+
+ @Value("${mosip.ida.kyc.exchange.skip:false}")
+ private boolean skipKycExchange;
+
+ @Override
+ public KycAuthResult doKycAuth(String relyingPartyId, String clientId, KycAuthDto kycAuthDto)
+ throws KycAuthException {
+ log.info("Started to build kyc request with transactionId : {} && clientId : {}",
+ kycAuthDto.getTransactionId(), clientId);
+ try {
+ IdaKycAuthRequest idaKycAuthRequest = new IdaKycAuthRequest();
+ idaKycAuthRequest.setId(skipKycExchange ? authOnlyId: kycId);
+ idaKycAuthRequest.setVersion(idaVersion);
+ idaKycAuthRequest.setRequestTime(HelperService.getUTCDateTime());
+ idaKycAuthRequest.setDomainUri(idaDomainUri);
+ idaKycAuthRequest.setEnv(idaEnv);
+ idaKycAuthRequest.setConsentObtained(true);
+ idaKycAuthRequest.setIndividualId(kycAuthDto.getIndividualId());
+ idaKycAuthRequest.setTransactionID(kycAuthDto.getTransactionId());
+ //Needed in pre-LTS version (such as 1.1.5.X)
+ Map requestedAuth = new HashMap<>();
+ idaKycAuthRequest.setRequestedAuth(requestedAuth);
+
+ helperService.setAuthRequest(kycAuthDto.getChallengeList(), idaKycAuthRequest);
+
+ //set signature header, body and invoke kyc auth endpoint
+ String requestBody = objectMapper.writeValueAsString(idaKycAuthRequest);
+ RequestEntity requestEntity = RequestEntity
+ .post(UriComponentsBuilder.fromUriString(skipKycExchange? authUrl : kycUrl).pathSegment(esignetAuthPartnerId, esignetAuthPartnerApiKey).build().toUri())
+ .contentType(MediaType.APPLICATION_JSON_UTF8)
+ .header(SIGNATURE_HEADER_NAME, helperService.getRequestSignature(requestBody))
+ .header(AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_NAME)
+ .body(requestBody);
+ ResponseEntity> responseEntity = restTemplate.exchange(requestEntity,
+ new ParameterizedTypeReference>() {});
+
+ if(responseEntity.getStatusCode().is2xxSuccessful() && responseEntity.getBody() != null) {
+ IdaResponseWrapper responseWrapper = responseEntity.getBody();
+ String psut = generatePsut(relyingPartyId, kycAuthDto.getIndividualId());
+ Tuple2 result = processKycResponse(responseWrapper, psut);
+ if(result != null) {
+ String kycToken = result.getT1();
+ String encryptedIdentityData = result.getT2();
+ if(encryptedIdentityData != null) {
+ identityDataStore.putEncryptedIdentityData(kycToken, psut, encryptedIdentityData);
+ }
+ if(kycToken != null) {
+ return new KycAuthResult(kycToken, psut);
+ }
+ }
+
+
+ log.error("Error response received from IDA status : {} && Errors: {}",
+ (responseWrapper.getResponse().isKycStatus() || responseWrapper.getResponse().isAuthStatus()), responseWrapper.getErrors());
+ throw new KycAuthException(CollectionUtils.isEmpty(responseWrapper.getErrors()) ?
+ ErrorConstants.AUTH_FAILED : responseWrapper.getErrors().get(0).getErrorCode());
+ }
+
+ log.error("Error response received from IDA (Kyc-auth) with status : {}", responseEntity.getStatusCode());
+ } catch (KycAuthException e) { throw e; } catch (Exception e) {
+ log.error("KYC-auth failed with transactionId : {} && clientId : {}", kycAuthDto.getTransactionId(),
+ clientId, e);
+ }
+ throw new KycAuthException(ErrorConstants.AUTH_FAILED);
+ }
+
+
+ private String generatePsut(String relyingPartyId, String individualId) throws Exception {
+ return tokenIdManager.generateTokenId(individualId, relyingPartyId);
+ }
+
+ private Tuple2 processKycResponse(IdaResponseWrapper responseWrapper, String psut) throws DecoderException, NoSuchAlgorithmException {
+ String kycToken = generateKycToken(responseWrapper.getTransactionID(), psut);
+ if(responseWrapper.getResponse() != null && responseWrapper.getResponse().isKycStatus()) {
+ IdaKycResponse response = responseWrapper.getResponse();
+ String encryptedIdentityData = response.getIdentity();
+ String combinedData = encryptedIdentityData;
+ String sessionKey = response.getSessionKey();
+ if(sessionKey != null) {
+ combinedData = CryptoUtil.encodeToURLSafeBase64(combineDataForDecryption(CryptoUtil.decodeURLSafeBase64(sessionKey), CryptoUtil.decodeURLSafeBase64(encryptedIdentityData)));
+ }
+ String thumbprint = response.getThumbprint();
+ if(thumbprint != null) {
+ combinedData = CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(CryptoUtil.decodeURLSafeBase64(combinedData), Hex.decodeHex(thumbprint), EMPTY));
+ }
+ return Tuples.of(kycToken, combinedData);
+ }
+ return Tuples.of(kycToken, null);
+ }
+
+ /**
+ * Combine data for decryption.
+ *
+ * @param encryptedSessionKey the encrypted session key
+ * @param encryptedData the encrypted data
+ * @return the string
+ */
+ private byte[] combineDataForDecryption(byte[] encryptedSessionKey, byte[] encryptedData) {
+ return CryptoUtil.combineByteArray(encryptedData, encryptedSessionKey, keySplitter);
+ }
+
+ private String generateKycToken(String transactionID, String authToken) throws DecoderException, NoSuchAlgorithmException {
+ String uuid = UUID.nameUUIDFromBytes(transactionID.getBytes()).toString();
+ return doGenerateKycToken(uuid, authToken);
+ }
+
+ private String doGenerateKycToken(String uuid, String idHash) throws DecoderException, NoSuchAlgorithmException {
+ try {
+ byte[] uuidBytes = uuid.getBytes();
+ byte[] idHashBytes = Hex.decodeHex(idHash);
+ ByteBuffer bBuffer = ByteBuffer.allocate(uuidBytes.length + idHashBytes.length);
+ bBuffer.put(uuidBytes);
+ bBuffer.put(idHashBytes);
+
+ byte[] kycTokenInputBytes = bBuffer.array();
+ return generateKeyedHash(kycTokenInputBytes);
+ } catch (DecoderException e) {
+ log.error("Error Generating KYC Token", e);
+ throw e;
+ }
+ }
+
+ public String generateKeyedHash(byte[] bytesToHash) throws java.security.NoSuchAlgorithmException {
+ try {
+ // Need to get secret from HSM
+ byte[] tokenSecret = CryptoUtil.decodeURLSafeBase64(kycTokenSecret);
+ MessageDigest messageDigest = MessageDigest.getInstance(HASH_ALGORITHM_NAME);
+ messageDigest.update(bytesToHash);
+ messageDigest.update(tokenSecret);
+ byte[] tokenHash = messageDigest.digest();
+
+ return TokenEncoderUtil.encodeBase58(tokenHash);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error generating Keyed Hash", e);
+ throw e;
+ }
+ }
+
+ @Override
+ public KycExchangeResult doKycExchange(String relyingPartyId, String clientId, KycExchangeDto kycExchangeDto)
+ throws KycExchangeException {
+ log.info("Started to build kyc-exchange request with transactionId : {} && clientId : {}",
+ kycExchangeDto.getTransactionId(), clientId);
+ try {
+ String psut = generatePsut(relyingPartyId, kycExchangeDto.getIndividualId());
+ String encryptedIdentityData = identityDataStore.getEncryptedIdentityData(kycExchangeDto.getKycToken(), psut);
+ Map idResDTO;
+ if(encryptedIdentityData != null) {
+ String decrptIdentityData = helperService.decrptData(encryptedIdentityData);
+ idResDTO = objectMapper.readValue(CryptoUtil.decodeURLSafeBase64(decrptIdentityData), Map.class);
+ } else {
+ idResDTO = Map.of();
+ }
+ Map> idInfo = IdInfoFetcher.getIdInfo(idResDTO);
+
+ String respJson =idInfo.isEmpty() ? null: buildKycExchangeResponse(psut, idInfo, kycExchangeDto.getAcceptedClaims(), List.of(kycExchangeDto.getClaimsLocales()), kycExchangeDto.getIndividualId());
+ IdaResponseWrapper responseWrapper = new IdaResponseWrapper<>();
+ IdaKycExchangeResponse respose = new IdaKycExchangeResponse();
+ responseWrapper.setResponse(respose);
+ respose.setEncryptedKyc(respJson);
+ return new KycExchangeResult(responseWrapper.getResponse().getEncryptedKyc());
+ } catch (KycExchangeException e) {
+ throw e;
+ } catch (Exception e) {e.printStackTrace();
+ log.error("IDA Kyc-exchange failed with clientId : {}", clientId, e);
+ }
+ throw new KycExchangeException();
+ }
+
+ public String buildKycExchangeResponse(String subject, Map> idInfo,
+ List consentedAttributes, List consentedLocales, String idVid) throws IdAuthenticationBusinessException {
+
+ log.info("Building claims response for PSU token: " + subject);
+
+ Map respMap = new HashMap<>();
+ Set uniqueConsentedLocales = new HashSet(consentedLocales);
+ Map mappedConsentedLocales = localesMapping(uniqueConsentedLocales);
+
+ respMap.put(SUBJECT, subject);
+
+ for (String attrib : consentedAttributes) {
+ if (attrib.equals(SUBJECT))
+ continue;
+ if (attrib.equals(consentedIndividualAttributeName)) {
+ respMap.put(attrib, idVid);
+ continue;
+ }
+ List idSchemaAttribute = idInfoHelper.getIdentityAttributesForIdName(attrib);
+ if (mappedConsentedLocales.size() > 0) {
+ addEntityForLangCodes(mappedConsentedLocales, idInfo, respMap, attrib, idSchemaAttribute);
+ }
+ }
+
+ try {
+ return signWithPayload(objectMapper.writeValueAsString(respMap));
+ } catch (JsonProcessingException e) {
+ throw new IdAuthenticationBusinessException(IdAuthenticationErrorConstants.UNABLE_TO_PROCESS, e);
+ }
+ }
+
+ public String signWithPayload(String data) {
+ JWTSignatureRequestDto request = new JWTSignatureRequestDto();
+ request.setApplicationId(kycExchSignApplicationId);
+ request.setDataToSign(CryptoUtil.encodeToURLSafeBase64(data.getBytes()));
+ request.setIncludeCertHash(false);
+ request.setIncludeCertificate(includeCertificate);
+ request.setIncludePayload(true);
+ request.setReferenceId(EMPTY);
+ return signatureService.jwtSign(request).getJwtSignedData();
+ }
+
+ private void addEntityForLangCodes(Map mappedConsentedLocales, Map> idInfo,
+ Map respMap, String consentedAttribute, List idSchemaAttributes)
+ throws IdAuthenticationBusinessException {
+
+ if (consentedAttribute.equals(consentedFaceAttributeName)) {
+ if (!idInfo.keySet().contains(BioMatchType.FACE.getIdMapping().getIdname())) {
+ log.info("Face Bio not found in DB. So not adding to response claims.");
+ return;
+ }
+ Map faceEntityInfoMap = idInfoHelper.getIdEntityInfoMap(BioMatchType.FACE, idInfo, null);
+ if (Objects.nonNull(faceEntityInfoMap)) {
+ String face = convertJP2ToJpeg(faceEntityInfoMap.get(CbeffDocType.FACE.getType().value()));
+ if (Objects.nonNull(face))
+ respMap.put(consentedAttribute, consentedPictureAttributePrefix + face);
+ }
+ return;
+ }
+
+ if (idSchemaAttributes.size() == 1) {
+ List idInfoList = idInfo.get(idSchemaAttributes.get(0));
+ if (Objects.isNull(idInfoList)) {
+ log.info("Data not available in Identity Info for the claim. So not adding to response claims. Claim Name: " + idSchemaAttributes.get(0));
+ return;
+ }
+ Map mappedLangCodes = langCodeMapping(idInfoList);
+ List availableLangCodes = getAvailableLangCodes(mappedConsentedLocales, mappedLangCodes);
+ if (availableLangCodes.size() == 1){
+ for (IdentityInfoDTO identityInfo : idInfoList) {
+ String langCode = mappedLangCodes.get(availableLangCodes.get(0));
+ if (identityInfo.getLanguage().equalsIgnoreCase(langCode)) {
+ respMap.put(consentedAttribute, identityInfo.getValue());
+ }
+ }
+ } else {
+ if (availableLangCodes.size() > 0) {
+ for (IdentityInfoDTO identityInfo : idInfoList) {
+ for (String availableLangCode : availableLangCodes) {
+ String langCode = mappedLangCodes.get(availableLangCode);
+ if (identityInfo.getLanguage().equalsIgnoreCase(langCode)) {
+ respMap.put(consentedAttribute + CLAIMS_LANG_SEPERATOR + availableLangCode,
+ identityInfo.getValue());
+ }
+ }
+ }
+ } else {
+ respMap.put(consentedAttribute, idInfoList.get(0).getValue());
+ }
+ }
+ } else {
+ if (consentedAttribute.equals(consentedAddressAttributeName)) {
+ if (mappedConsentedLocales.size() > 1) {
+ for (String consentedLocale: mappedConsentedLocales.keySet()) {
+ String consentedLocaleValue = mappedConsentedLocales.get(consentedLocale);
+ if (addressSubsetAttributes.length == 0) {
+ log.info("No address subset attributes configured. Will return the address with formatted attribute.");
+ addFormattedAddress(idSchemaAttributes, idInfo, consentedLocaleValue, respMap, true,
+ CLAIMS_LANG_SEPERATOR + consentedLocaleValue);
+ continue;
+ }
+ addAddressClaim(addressSubsetAttributes, idInfo, consentedLocaleValue, respMap, true,
+ CLAIMS_LANG_SEPERATOR + consentedLocaleValue);
+ }
+ } else {
+ String consentedLocale = mappedConsentedLocales.keySet().iterator().next();
+ String consentedLocaleValue = mappedConsentedLocales.get(consentedLocale);
+ if (addressSubsetAttributes.length == 0) {
+ log.info("No address subset attributes configured. Will return the address with formatted attribute.");
+ addFormattedAddress(idSchemaAttributes, idInfo, consentedLocaleValue, respMap, false, "");
+ return;
+ }
+
+ addAddressClaim(addressSubsetAttributes, idInfo, consentedLocaleValue, respMap, false, "");
+ }
+ }
+ }
+ }
+
+ private void addFormattedAddress(List idSchemaAttributes, Map> idInfo, String localeValue,
+ Map respMap, boolean addLocale, String localeAppendValue) throws IdAuthenticationBusinessException {
+ boolean langCodeFound = false;
+ Map addressMap = new HashMap<>();
+ StringBuilder identityInfoValue = new StringBuilder();
+ for (String schemaAttrib: idSchemaAttributes) {
+ List idSchemaSubsetAttributes = idInfoHelper.getIdentityAttributesForIdName(schemaAttrib);
+ for (String idSchemaAttribute : idSchemaSubsetAttributes) {
+ List idInfoList = idInfo.get(idSchemaAttribute);
+ Map mappedLangCodes = langCodeMapping(idInfoList);
+ if (identityInfoValue.length() > 0) {
+ identityInfoValue.append(addressValueSeparator);
+ }
+ if (mappedLangCodes.keySet().contains(localeValue)) {
+ String langCode = mappedLangCodes.get(localeValue);
+ for (IdentityInfoDTO identityInfo : idInfoList) {
+ if (identityInfoValue.length() > 0) {
+ identityInfoValue.append(addressValueSeparator);
+ }
+ if (identityInfo.getLanguage().equals(langCode)) {
+ langCodeFound = true;
+ identityInfoValue.append(identityInfo.getValue());
+ }
+ }
+ } else {
+ if (Objects.nonNull(idInfoList) && idInfoList.size() == 1) {
+ identityInfoValue.append(idInfoList.get(0).getValue());
+ }
+ }
+ }
+ }
+ //String identityInfoValueStr = identityInfoValue.toString();
+ //String trimmedValue = identityInfoValueStr.substring(0, identityInfoValueStr.lastIndexOf(addressValueSeparator));
+ addressMap.put(ADDRESS_FORMATTED + localeAppendValue, identityInfoValue.toString());
+ if (langCodeFound && addLocale)
+ respMap.put(consentedAddressAttributeName + localeAppendValue, addressMap);
+ else
+ respMap.put(consentedAddressAttributeName, addressMap);
+ }
+
+ private void addAddressClaim(String[] addressAttributes, Map> idInfo, String consentedLocaleValue,
+ Map respMap, boolean addLocale, String localeAppendValue) throws IdAuthenticationBusinessException {
+ boolean langCodeFound = false; //added for language data not available in identity info (Eg: fr)
+ Map addressMap = new HashMap<>();
+ for (String addressAttribute : addressAttributes) {
+ List idSchemaSubsetAttributes = idInfoHelper.getIdentityAttributesForIdName(addressAttribute);
+ StringBuilder identityInfoValue = new StringBuilder();
+ for (String idSchemaAttribute : idSchemaSubsetAttributes) {
+ List idInfoList = idInfo.get(idSchemaAttribute);
+ Map mappedLangCodes = langCodeMapping(idInfoList);
+ if (identityInfoValue.length() > 0) {
+ identityInfoValue.append(addressValueSeparator);
+ }
+ if (mappedLangCodes.keySet().contains(consentedLocaleValue)) {
+ String langCode = mappedLangCodes.get(consentedLocaleValue);
+ for (IdentityInfoDTO identityInfo : idInfoList) {
+ if (identityInfoValue.length() > 0) {
+ identityInfoValue.append(addressValueSeparator);
+ }
+ if (identityInfo.getLanguage().equals(langCode)) {
+ langCodeFound = true;
+ identityInfoValue.append(identityInfo.getValue());
+ }
+ }
+ } else {
+ if (Objects.nonNull(idInfoList) && idInfoList.size() == 1) {
+ identityInfoValue.append(idInfoList.get(0).getValue());
+ }
+ }
+ }
+ // Added below condition to skip if the data is not available in DB. MOSIP-26472
+ if (identityInfoValue.toString().trim().length() > 0)
+ addressMap.put(addressAttribute + localeAppendValue, identityInfoValue.toString());
+ }
+ if (langCodeFound && addLocale)
+ respMap.put(consentedAddressAttributeName + localeAppendValue, addressMap);
+ else
+ respMap.put(consentedAddressAttributeName, addressMap);
+ }
+
+ private String convertJP2ToJpeg(String jp2Image) {
+ try {
+ ConvertRequestDto convertRequestDto = new ConvertRequestDto();
+ convertRequestDto.setVersion(FACE_ISO_NUMBER);
+ convertRequestDto.setInputBytes(CryptoUtil.decodeBase64(jp2Image));// TODO check url safe / plain
+ byte[] image = FaceDecoder.convertFaceISOToImageBytes(convertRequestDto);
+ return CryptoUtil.encodeBase64(image);// TODO check url safe / plain
+ } catch(Exception exp) {
+ log.error("Error Converting JP2 To JPEG. " + exp.getMessage(), exp);
+ }
+ return null;
+ }
+
+ private Map localesMapping(Set locales) {
+
+ Map mappedLocales = new HashMap<>();
+ for (String locale : locales) {
+ if (locale.trim().length() == 0)
+ continue;
+ mappedLocales.put(locale, locale.substring(0, 2));
+ }
+ return mappedLocales;
+ }
+
+ private Map langCodeMapping(List idInfoList) {
+
+ Map mappedLangCodes = new HashMap<>();
+ if (Objects.nonNull(idInfoList)) {
+ for (IdentityInfoDTO idInfo : idInfoList) {
+ if (Objects.nonNull(idInfo.getLanguage())) {
+ mappedLangCodes.put(idInfo.getLanguage().substring(0,2), idInfo.getLanguage());
+ }
+ }
+ }
+ return mappedLangCodes;
+ }
+
+ private List getAvailableLangCodes(Map mappedLocales, Map mappedLangCodes) {
+ List availableLangCodes = new ArrayList<>();
+ for (String entry: mappedLocales.keySet()) {
+ String locale = mappedLocales.get(entry);
+ if (mappedLangCodes.keySet().contains(locale)) {
+ availableLangCodes.add(locale);
+ }
+ }
+ return availableLangCodes;
+ }
+
+ @Override
+ public SendOtpResult sendOtp(String relyingPartyId, String clientId, SendOtpDto sendOtpDto) throws SendOtpException {
+ log.info("Started to build send-otp request with transactionId : {} && clientId : {}",
+ sendOtpDto.getTransactionId(), clientId);
+ try {
+ IdaSendOtpRequest idaSendOtpRequest = new IdaSendOtpRequest();
+ idaSendOtpRequest.setOtpChannel(sendOtpDto.getOtpChannels());
+ idaSendOtpRequest.setIndividualId(sendOtpDto.getIndividualId());
+ idaSendOtpRequest.setTransactionID(sendOtpDto.getTransactionId());
+ return helperService.sendOTP(relyingPartyId, clientId, idaSendOtpRequest);
+ } catch (SendOtpException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("send-otp failed with clientId : {}", clientId, e);
+ }
+ throw new SendOtpException();
+ }
+
+ @Override
+ public boolean isSupportedOtpChannel(String channel) {
+ return channel != null && otpChannels.contains(channel.toLowerCase());
+ }
+
+ @Override
+ public List getAllKycSigningCertificates() throws KycSigningCertificateException {
+ try {
+ String authToken = authTransactionHelper.getAuthToken();
+
+ RequestEntity requestEntity = RequestEntity
+ .get(UriComponentsBuilder.fromUriString(getCertsUrl).queryParam("applicationId", applicationId).queryParam("referenceId", referenceId).build().toUri())
+ .header(HttpHeaders.COOKIE, "Authorization=" + authToken)
+ .build();
+
+ ResponseEntity> responseEntity = restTemplate.exchange(requestEntity,
+ new ParameterizedTypeReference>() {});
+
+ if(responseEntity.getStatusCode().is2xxSuccessful() && responseEntity.getBody() != null) {
+ ResponseWrapper responseWrapper = responseEntity.getBody();
+ if(responseWrapper.getResponse() != null && responseWrapper.getResponse().getAllCertificates() != null) {
+ return responseWrapper.getResponse().getAllCertificates();
+ }
+ log.error("Error response received from getAllSigningCertificates with errors: {}",
+ responseWrapper.getErrors());
+ throw new KycSigningCertificateException(CollectionUtils.isEmpty(responseWrapper.getErrors()) ?
+ ErrorConstants.KYC_SIGNING_CERTIFICATE_FAILED : responseWrapper.getErrors().get(0).getErrorCode());
+ }
+ log.error("Error response received from getAllSigningCertificates with status : {}", responseEntity.getStatusCode());
+ } catch (KycSigningCertificateException e) { throw e; } catch (Exception e) {
+ log.error("getAllKycSigningCertificates failed with clientId : {}", clientId, e);
+ }
+ throw new KycSigningCertificateException();
+ }
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImpl.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImpl.java
new file mode 100644
index 00000000000..245a7821ebf
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImpl.java
@@ -0,0 +1,174 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.service;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.mosip.authentication.esignet.integration.dto.*;
+import io.mosip.esignet.api.dto.AuthChallenge;
+import io.mosip.esignet.api.dto.KeyBindingResult;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.KeyBindingException;
+import io.mosip.esignet.api.exception.KycAuthException;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.esignet.api.spi.KeyBinder;
+import io.mosip.esignet.api.util.ErrorConstants;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.MediaType;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@ConditionalOnProperty(value = "mosip.esignet.integration.key-binder", havingValue = "IdaKeyBinderImpl")
+@Component
+@Slf4j
+public class IdaKeyBinderImpl implements KeyBinder {
+
+ private static final Map> supportedFormats = new HashMap<>();
+ static {
+ supportedFormats.put("OTP", Arrays.asList("alpha-numeric"));
+ supportedFormats.put("PIN", Arrays.asList("number"));
+ supportedFormats.put("BIO", Arrays.asList("encoded-json"));
+ supportedFormats.put("WLA", Arrays.asList("jwt"));
+ }
+
+ private static final String PARTNER_ID_HEADER = "partner-id";
+ private static final String PARTNER_API_KEY_HEADER = "partner-api-key";
+ public static final String SIGNATURE_HEADER_NAME = "signature";
+ public static final String AUTHORIZATION_HEADER_NAME = "Authorization";
+ public static final String REQUIRED_HEADERS_MISSING = "required_header_missing";
+
+ @Value("${mosip.esignet.binder.ida.key-binding-url}")
+ private String keyBinderUrl;
+
+ @Value("${mosip.esignet.binder.ida-binding-id:mosip.identity.keybinding}")
+ private String keyBindingId;
+
+ @Value("${mosip.esignet.authenticator.ida-version:1.0}")
+ private String idaVersion;
+
+ @Value("${mosip.esignet.authenticator.ida-domainUri}")
+ private String idaDomainUri;
+
+ @Value("${mosip.esignet.authenticator.ida-env:Staging}")
+ private String idaEnv;
+
+ @Autowired
+ private HelperService helperService;
+
+ @Autowired
+ private ObjectMapper objectMapper;
+
+ @Autowired
+ private RestTemplate restTemplate;
+
+ @Override
+ public SendOtpResult sendBindingOtp(String individualId, List otpChannels, Map requestHeaders)
+ throws SendOtpException {
+ log.info("Started to send-binding-otp request");
+ try {
+ if(StringUtils.isEmpty(requestHeaders.get(PARTNER_ID_HEADER)) || StringUtils.isEmpty(requestHeaders.get(PARTNER_API_KEY_HEADER)))
+ throw new SendOtpException(REQUIRED_HEADERS_MISSING);
+
+ IdaSendOtpRequest idaSendOtpRequest = new IdaSendOtpRequest();
+ idaSendOtpRequest.setOtpChannel(otpChannels);
+ idaSendOtpRequest.setIndividualId(individualId);
+ idaSendOtpRequest.setTransactionID(helperService.getTransactionId(HelperService.generateHash(individualId.trim())));
+ return helperService.sendOTP(requestHeaders.get(PARTNER_ID_HEADER),
+ requestHeaders.get(PARTNER_API_KEY_HEADER), idaSendOtpRequest);
+ } catch (SendOtpException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("send-binding-otp failed with requestHeaders : {}", requestHeaders, e);
+ }
+ throw new SendOtpException();
+ }
+
+ @Override
+ public KeyBindingResult doKeyBinding(String individualId, List challengeList, Map publicKeyJWK,
+ String bindAuthFactorType, Map requestHeaders) throws KeyBindingException {
+ log.info("Started to key-binding request for auth-factor-type {}", bindAuthFactorType);
+ if(StringUtils.isEmpty(requestHeaders.get(PARTNER_ID_HEADER)) || StringUtils.isEmpty(requestHeaders.get(PARTNER_API_KEY_HEADER)))
+ throw new KeyBindingException(REQUIRED_HEADERS_MISSING);
+
+ try {
+ KeyBindingRequest keyBindingRequest = new KeyBindingRequest();
+ keyBindingRequest.setId(keyBindingId);
+ keyBindingRequest.setVersion(idaVersion);
+ keyBindingRequest.setRequestTime(HelperService.getUTCDateTime());
+ keyBindingRequest.setDomainUri(idaDomainUri);
+ keyBindingRequest.setEnv(idaEnv);
+ keyBindingRequest.setConsentObtained(true);
+ keyBindingRequest.setIndividualId(individualId);
+ keyBindingRequest.setTransactionID(helperService.getTransactionId(HelperService.generateHash(individualId.trim())));
+ helperService.setAuthRequest(challengeList, keyBindingRequest);
+
+ KeyBindingRequest.IdentityKeyBinding identityKeyBinding = new KeyBindingRequest.IdentityKeyBinding();
+ identityKeyBinding.setPublicKeyJWK(publicKeyJWK);
+ identityKeyBinding.setAuthFactorType(bindAuthFactorType);
+ keyBindingRequest.setIdentityKeyBinding(identityKeyBinding);
+
+ //set signature header, body and invoke kyc auth endpoint
+ String requestBody = objectMapper.writeValueAsString(keyBindingRequest);
+ RequestEntity requestEntity = RequestEntity
+ .post(UriComponentsBuilder.fromUriString(keyBinderUrl).pathSegment(requestHeaders.getOrDefault(PARTNER_ID_HEADER, PARTNER_ID_HEADER),
+ requestHeaders.getOrDefault(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER)).build().toUri())
+ .contentType(MediaType.APPLICATION_JSON_UTF8)
+ .header(SIGNATURE_HEADER_NAME, helperService.getRequestSignature(requestBody))
+ .header(AUTHORIZATION_HEADER_NAME, AUTHORIZATION_HEADER_NAME)
+ .body(requestBody);
+ ResponseEntity> responseEntity = restTemplate.exchange(requestEntity,
+ new ParameterizedTypeReference>() {});
+
+ if(responseEntity.getStatusCode().is2xxSuccessful() && responseEntity.getBody() != null) {
+ IdaResponseWrapper responseWrapper = responseEntity.getBody();
+ if(responseWrapper.getResponse() == null) {
+ log.error("Error response received from IDA (Key-binding) Errors: {}", responseWrapper.getErrors());
+ throw new KeyBindingException(CollectionUtils.isEmpty(responseWrapper.getErrors()) ?
+ ErrorConstants.KEY_BINDING_FAILED : responseWrapper.getErrors().get(0).getErrorCode());
+ }
+
+ if(!responseWrapper.getResponse().isBindingAuthStatus()) {
+ log.error("Binding-Auth-status : {}", responseWrapper.getResponse().isBindingAuthStatus());
+ throw new KeyBindingException(ErrorConstants.BINDING_AUTH_FAILED);
+ }
+
+ KeyBindingResult keyBindingResult = new KeyBindingResult();
+ keyBindingResult.setCertificate(responseWrapper.getResponse().getIdentityCertificate());
+ keyBindingResult.setPartnerSpecificUserToken(responseWrapper.getResponse().getAuthToken());
+ return keyBindingResult;
+ }
+
+ log.error("Error response received from IDA (Key-binding) with status : {}", responseEntity.getStatusCode());
+ } catch (KeyBindingException e) {
+ throw e;
+ } catch (Exception e) {
+ log.error("Key-binding failed with headers: {}", requestHeaders, e);
+ }
+ throw new KeyBindingException(ErrorConstants.KEY_BINDING_FAILED);
+ }
+
+ @Override
+ public List getSupportedChallengeFormats(String authFactorType) {
+ return supportedFormats.getOrDefault(authFactorType, Arrays.asList());
+ }
+
+}
diff --git a/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/TokenEncoderUtil.java b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/TokenEncoderUtil.java
new file mode 100644
index 00000000000..11722819ff8
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/main/java/io/mosip/authentication/esignet/integration/service/TokenEncoderUtil.java
@@ -0,0 +1,61 @@
+package io.mosip.authentication.esignet.integration.service;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * The Class TokenEncoderUtil is the utility class to encode base58 for the generated token.
+ *
+ * @author Mahammed Taheer
+ */
+public final class TokenEncoderUtil {
+
+ private static final char[] BASE58_ALPHANUMERIC = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
+
+ private static final char ENCODED_0 = BASE58_ALPHANUMERIC[0];
+
+ public static String encodeBase58(final byte[] dataToEncode) {
+ if (Objects.isNull(dataToEncode) || dataToEncode.length == 0) {
+ return "";
+ }
+
+ final char[] encoded = new char[dataToEncode.length * 2];
+ final byte[] copy = Arrays.copyOf(dataToEncode, dataToEncode.length);
+
+ int zeros = 0;
+ while (zeros < dataToEncode.length && dataToEncode[zeros] == 0) {
+ ++zeros;
+ }
+
+ int inputIndex = zeros;
+ int outputIndex = encoded.length;
+ while (inputIndex < copy.length) {
+ encoded[--outputIndex] = BASE58_ALPHANUMERIC[divmod(copy, inputIndex, 256, 58)];
+ if (copy[inputIndex] == 0) {
+ ++inputIndex;
+ }
+ }
+
+ while (outputIndex < encoded.length && encoded[outputIndex] == ENCODED_0) {
+ ++outputIndex;
+ }
+ while (--zeros >= 0) {
+ encoded[--outputIndex] = ENCODED_0;
+ }
+
+ return new String(encoded, outputIndex, encoded.length - outputIndex);
+ }
+
+ private static byte divmod(byte[] number, int firstDigit, int base, int divisor) {
+ int remainder = 0;
+ for (int i = firstDigit; i < number.length; i++) {
+ int digit = (int) number[i] & 0xff;
+ int temp = remainder * base + digit;
+ number[i] = (byte) (temp / divisor);
+ remainder = temp % divisor;
+ }
+ return (byte) remainder;
+ }
+
+
+}
diff --git a/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/HelperServiceTest.java b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/HelperServiceTest.java
new file mode 100644
index 00000000000..8528d4b3d91
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/HelperServiceTest.java
@@ -0,0 +1,244 @@
+package io.mosip.authentication.esignet.integration.service;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.mosip.authentication.esignet.integration.dto.*;
+import io.mosip.authentication.esignet.integration.dto.Error;
+import io.mosip.esignet.api.dto.AuthChallenge;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.kernel.crypto.jce.core.CryptoCore;
+import io.mosip.kernel.keymanagerservice.util.KeymanagerUtil;
+import io.mosip.kernel.signature.dto.JWTSignatureResponseDto;
+import io.mosip.kernel.signature.service.SignatureService;
+import org.apache.commons.lang3.NotImplementedException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class HelperServiceTest {
+
+ @InjectMocks
+ private HelperService helperService;
+
+ @Mock
+ private KeymanagerUtil keymanagerUtil;
+
+ @Mock
+ private SignatureService signatureService;
+
+ @Mock
+ private RestTemplate restTemplate;
+
+ @Mock
+ private CryptoCore cryptoCore;
+
+ String partnerId = "test";
+ String partnerAPIKey = "test-api-key";
+
+ ObjectMapper objectMapper = new ObjectMapper();
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ReflectionTestUtils.setField(helperService, "sendOtpUrl", "https://test/test");
+ ReflectionTestUtils.setField(helperService, "idaPartnerCertificateUrl", "https://test/test");
+ ReflectionTestUtils.setField(helperService, "symmetricAlgorithm", "AES");
+ ReflectionTestUtils.setField(helperService, "symmetricKeyLength", 256);
+ ReflectionTestUtils.setField(helperService, "objectMapper", objectMapper);
+ }
+
+ @Test
+ public void sendOtp_requestSignatureFailed_thenFail() {
+ JWTSignatureResponseDto jwtSignatureResponseDto = new JWTSignatureResponseDto();
+ jwtSignatureResponseDto.setJwtSignedData("test-jwt");
+ Mockito.when(signatureService.jwtSign(Mockito.any())).thenThrow(RuntimeException.class);
+ IdaSendOtpRequest sendOtpRequest = new IdaSendOtpRequest();
+ Assert.assertThrows(Exception.class, () -> helperService.sendOTP(partnerId, partnerAPIKey, sendOtpRequest));
+ }
+
+ @Test
+ public void sendOtp_withNullResponse_thenFail() {
+ JWTSignatureResponseDto jwtSignatureResponseDto = new JWTSignatureResponseDto();
+ jwtSignatureResponseDto.setJwtSignedData("test-jwt");
+ Mockito.when(signatureService.jwtSign(Mockito.any())).thenReturn(jwtSignatureResponseDto);
+
+ ResponseEntity responseEntity = new ResponseEntity(HttpStatus.OK);
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.any())).thenReturn(responseEntity);
+ IdaSendOtpRequest sendOtpRequest = new IdaSendOtpRequest();
+ Assert.assertThrows(SendOtpException.class, () -> helperService.sendOTP(partnerId, partnerAPIKey, sendOtpRequest));
+ }
+
+ @Test
+ public void sendOtp_withValidResponse_thenPass() throws Exception {
+ JWTSignatureResponseDto jwtSignatureResponseDto = new JWTSignatureResponseDto();
+ jwtSignatureResponseDto.setJwtSignedData("test-jwt");
+ Mockito.when(signatureService.jwtSign(Mockito.any())).thenReturn(jwtSignatureResponseDto);
+
+ IdaSendOtpResponse idaSendOtpResponse = new IdaSendOtpResponse();
+ idaSendOtpResponse.setTransactionID("123456788");
+ IdaOtpResponse idaOtpResponse = new IdaOtpResponse();
+ idaOtpResponse.setMaskedEmail("masked-mail");
+ new IdaOtpResponse().setMaskedMobile("masked-mobile");
+ idaSendOtpResponse.setResponse(idaOtpResponse);
+ ResponseEntity responseEntity = new ResponseEntity(
+ idaSendOtpResponse, HttpStatus.OK);
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.any())).thenReturn(responseEntity);
+ IdaSendOtpRequest sendOtpRequest = new IdaSendOtpRequest();
+ sendOtpRequest.setTransactionID("123456788");
+ SendOtpResult sendOtpResult = helperService.sendOTP(partnerId, partnerAPIKey, sendOtpRequest);
+ Assert.assertEquals(idaSendOtpResponse.getTransactionID(), sendOtpResult.getTransactionId());
+ Assert.assertEquals(idaOtpResponse.getMaskedEmail(), sendOtpResult.getMaskedEmail());
+ Assert.assertEquals(idaOtpResponse.getMaskedMobile(), sendOtpResult.getMaskedMobile());
+ }
+
+ @Test
+ public void sendOtp_withErrorResponse_thenFail() {
+ JWTSignatureResponseDto jwtSignatureResponseDto = new JWTSignatureResponseDto();
+ jwtSignatureResponseDto.setJwtSignedData("test-jwt");
+ Mockito.when(signatureService.jwtSign(Mockito.any())).thenReturn(jwtSignatureResponseDto);
+
+ IdaSendOtpResponse idaSendOtpResponse = new IdaSendOtpResponse();
+ idaSendOtpResponse.setTransactionID("123456788");
+ idaSendOtpResponse.setErrors(Arrays.asList(new Error("otp-error", "otp-error")));
+ ResponseEntity responseEntity = new ResponseEntity(
+ idaSendOtpResponse, HttpStatus.OK);
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.any())).thenReturn(responseEntity);
+
+ IdaSendOtpRequest sendOtpRequest = new IdaSendOtpRequest();
+ sendOtpRequest.setTransactionID("123456788");
+ try {
+ helperService.sendOTP(partnerId, partnerAPIKey, sendOtpRequest);
+ } catch (SendOtpException e) {
+ Assert.assertEquals("otp-error", e.getErrorCode());
+ } catch (JsonProcessingException e) {
+ Assert.fail();
+ }
+ }
+
+ @Test
+ public void setAuthRequest_withInvalidChallengeType_thenFail() {
+ List challengeList = new ArrayList<>();
+ AuthChallenge authChallenge = new AuthChallenge();
+ authChallenge.setChallenge("test");
+ authChallenge.setAuthFactorType("Test");
+ challengeList.add(authChallenge);
+ Assert.assertThrows(NotImplementedException.class,
+ () -> helperService.setAuthRequest(challengeList, new IdaKycAuthRequest()));
+ }
+
+ @Test
+ public void setAuthRequest_withOTPChallengeType_thenPass() throws Exception {
+ List challengeList = new ArrayList<>();
+ AuthChallenge authChallenge = new AuthChallenge();
+ authChallenge.setChallenge("111333");
+ authChallenge.setAuthFactorType("otp");
+ authChallenge.setFormat("numeric");
+ challengeList.add(authChallenge);
+
+ Mockito.when(restTemplate.getForObject("https://test/test", String.class)).thenReturn("test-certificate");
+ Mockito.when(keymanagerUtil.convertToCertificate(Mockito.any(String.class))).thenReturn(TestUtil.getCertificate());
+ Mockito.when(cryptoCore.asymmetricEncrypt(Mockito.any(), Mockito.any())).thenReturn("test".getBytes());
+
+ IdaKycAuthRequest idaKycAuthRequest = new IdaKycAuthRequest();
+ helperService.setAuthRequest(challengeList, idaKycAuthRequest);
+ Assert.assertNotNull(idaKycAuthRequest.getRequest());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestSessionKey());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestHMAC());
+ Assert.assertNotNull(idaKycAuthRequest.getThumbprint());
+ }
+
+ @Test
+ public void setAuthRequest_withPINChallengeType_thenPass() throws Exception {
+ List challengeList = new ArrayList<>();
+ AuthChallenge authChallenge = new AuthChallenge();
+ authChallenge.setChallenge("111333");
+ authChallenge.setAuthFactorType("pin");
+ authChallenge.setFormat("numeric");
+ challengeList.add(authChallenge);
+
+ Mockito.when(restTemplate.getForObject("https://test/test", String.class)).thenReturn("test-certificate");
+ Mockito.when(keymanagerUtil.convertToCertificate(Mockito.any(String.class))).thenReturn(TestUtil.getCertificate());
+ Mockito.when(cryptoCore.asymmetricEncrypt(Mockito.any(), Mockito.any())).thenReturn("test".getBytes());
+
+ IdaKycAuthRequest idaKycAuthRequest = new IdaKycAuthRequest();
+ helperService.setAuthRequest(challengeList, idaKycAuthRequest);
+ Assert.assertNotNull(idaKycAuthRequest.getRequest());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestSessionKey());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestHMAC());
+ Assert.assertNotNull(idaKycAuthRequest.getThumbprint());
+ }
+
+ @Test
+ public void setAuthRequest_withBIOChallengeType_thenPass() throws Exception {
+ IdaKycAuthRequest.Biometric biometric = new IdaKycAuthRequest.Biometric();
+ biometric.setData("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0cmFuc2FjdGlvbklkIjoiMTIzNDU2Nzg5MCIsIm5hbWUiOiJKb2huIERvZSIsImlhdCI6MTUxNjIzOTAyMn0=.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
+ List list = new ArrayList<>();
+ list.add(biometric);
+ String value = objectMapper.writeValueAsString(list);
+
+ List challengeList = new ArrayList<>();
+ AuthChallenge authChallenge = new AuthChallenge();
+ authChallenge.setChallenge(HelperService.b64Encode(value));
+ authChallenge.setAuthFactorType("bio");
+ authChallenge.setFormat("numeric");
+ challengeList.add(authChallenge);
+
+ Mockito.when(restTemplate.getForObject("https://test/test", String.class)).thenReturn("test-certificate");
+ Mockito.when(keymanagerUtil.convertToCertificate(Mockito.any(String.class))).thenReturn(TestUtil.getCertificate());
+ Mockito.when(cryptoCore.asymmetricEncrypt(Mockito.any(), Mockito.any())).thenReturn("test".getBytes());
+
+ IdaKycAuthRequest idaKycAuthRequest = new IdaKycAuthRequest();
+ helperService.setAuthRequest(challengeList, idaKycAuthRequest);
+ Assert.assertNotNull(idaKycAuthRequest.getRequest());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestSessionKey());
+ Assert.assertNotNull(idaKycAuthRequest.getRequestHMAC());
+ Assert.assertNotNull(idaKycAuthRequest.getThumbprint());
+ }
+
+ @Test
+ public void getIdaPartnerCertificate_withUnsetPartnerCertificate_thenPass() throws Exception {
+ Mockito.when(restTemplate.getForObject("https://test/test", String.class)).thenReturn("test-certificate");
+ Certificate certificate = TestUtil.getCertificate();
+ Mockito.when(keymanagerUtil.convertToCertificate(Mockito.any(String.class))).thenReturn(certificate);
+ Assert.assertEquals(certificate, helperService.getIdaPartnerCertificate());
+ }
+
+ @Test
+ public void getIdaPartnerCertificate_withExpiredPartnerCertificate_thenPass() throws Exception {
+ Mockito.when(restTemplate.getForObject("https://test/test", String.class)).thenReturn("test-certificate", "test-certificate");
+ Certificate certificate = TestUtil.getCertificate();
+ Mockito.when(keymanagerUtil.convertToCertificate(Mockito.any(String.class))).thenReturn(TestUtil.getExpiredCertificate(), certificate);
+ Assert.assertEquals(certificate, helperService.getIdaPartnerCertificate());
+ }
+
+ @Test
+ public void getRequestSignature_validation() {
+ JWTSignatureResponseDto jwtSignatureResponseDto = new JWTSignatureResponseDto();
+ jwtSignatureResponseDto.setJwtSignedData("test-jwt");
+ Mockito.when(signatureService.jwtSign(Mockito.any())).thenReturn(jwtSignatureResponseDto);
+ Assert.assertEquals("test-jwt", helperService.getRequestSignature("test-request-value"));
+ }
+}
diff --git a/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImplTest.java b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImplTest.java
new file mode 100644
index 00000000000..21af9462e40
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaAuthenticatorImplTest.java
@@ -0,0 +1,425 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.service;
+
+import static org.mockito.ArgumentMatchers.any;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.client.RestTemplate;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.mosip.authentication.esignet.integration.dto.GetAllCertificatesResponse;
+import io.mosip.authentication.esignet.integration.dto.IdaKycExchangeResponse;
+import io.mosip.authentication.esignet.integration.dto.IdaResponseWrapper;
+import io.mosip.authentication.esignet.integration.helper.AuthTransactionHelper;
+import io.mosip.esignet.api.dto.KycExchangeDto;
+import io.mosip.esignet.api.dto.KycExchangeResult;
+import io.mosip.esignet.api.dto.KycSigningCertificateData;
+import io.mosip.esignet.api.dto.SendOtpDto;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.KycExchangeException;
+import io.mosip.esignet.api.exception.KycSigningCertificateException;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.kernel.core.exception.ServiceError;
+import io.mosip.kernel.core.http.ResponseWrapper;
+
+@SpringBootTest
+@RunWith(MockitoJUnitRunner.class)
+public class IdaAuthenticatorImplTest {
+
+ @InjectMocks
+ IdaAuthenticatorImpl idaAuthenticatorImpl;
+
+ @Mock
+ ObjectMapper mapper;
+
+ @Mock
+ RestTemplate restTemplate;
+
+ @Mock
+ HelperService helperService;
+
+ @Mock
+ AuthTransactionHelper authTransactionHelper;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ ReflectionTestUtils.setField(helperService, "sendOtpUrl", "https:/");
+ ReflectionTestUtils.setField(helperService, "idaPartnerCertificateUrl", "https://test");
+ ReflectionTestUtils.setField(helperService, "symmetricAlgorithm", "AES");
+ ReflectionTestUtils.setField(helperService, "symmetricKeyLength", 256);
+
+ ReflectionTestUtils.setField(idaAuthenticatorImpl, "kycExchangeUrl", "https://dev.mosip.net");
+ ReflectionTestUtils.setField(idaAuthenticatorImpl, "idaVersion", "VersionIDA");
+ ReflectionTestUtils.setField(idaAuthenticatorImpl, "kycAuthUrl", "https://testkycAuthUrl");
+ ReflectionTestUtils.setField(idaAuthenticatorImpl, "getCertsUrl", "https://testGetCertsUrl");
+ ReflectionTestUtils.setField(idaAuthenticatorImpl, "otpChannels", Arrays.asList("otp", "pin", "bio"));
+ }
+//TODO fix the test cases
+// @Test
+// public void doKycAuth_withInvalidDetails_throwsException() throws Exception {
+// KycAuthDto kycAuthDto = new KycAuthDto();
+// kycAuthDto.setIndividualId("IND1234");
+// kycAuthDto.setTransactionId("TRAN1234");
+// AuthChallenge authChallenge = new AuthChallenge();
+// authChallenge.setAuthFactorType("PIN");
+// authChallenge.setChallenge("111111");
+// List authChallengeList = new ArrayList<>();
+// authChallengeList.add(authChallenge);
+// kycAuthDto.setChallengeList(authChallengeList);
+//
+// Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+// Mockito.when(restTemplate.exchange(Mockito.>any(),
+// Mockito.>>any())).thenReturn(null);
+//
+// Assert.assertThrows(KycAuthException.class,
+// () -> idaAuthenticatorImpl.doKycAuth("relyingId", "clientId", kycAuthDto));
+// }
+//
+// @Test
+// public void doKycAuth_withValidDetails_thenPass() throws Exception {
+// KycAuthDto kycAuthDto = new KycAuthDto();
+// kycAuthDto.setIndividualId("IND1234");
+// kycAuthDto.setTransactionId("TRAN1234");
+// AuthChallenge authChallenge = new AuthChallenge();
+// authChallenge.setAuthFactorType("OTP");
+// authChallenge.setChallenge("111111");
+// List authChallengeList = new ArrayList<>();
+// authChallengeList.add(authChallenge);
+// kycAuthDto.setChallengeList(authChallengeList);
+//
+// Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+//
+// IdaKycAuthResponse idaKycAuthResponse = new IdaKycAuthResponse();
+// idaKycAuthResponse.setAuthToken("authToken1234");
+// idaKycAuthResponse.setKycToken("kycToken1234");
+// idaKycAuthResponse.setKycStatus(true);
+//
+// IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+// idaResponseWrapper.setResponse(idaKycAuthResponse);
+// idaResponseWrapper.setTransactionID("TRAN123");
+// idaResponseWrapper.setVersion("VER1");
+//
+// ResponseEntity> responseEntity = new ResponseEntity>(
+// idaResponseWrapper, HttpStatus.OK);
+//
+// Mockito.when(restTemplate.exchange(Mockito.>any(),
+// Mockito.>>any()))
+// .thenReturn(responseEntity);
+//
+// KycAuthResult kycAuthResult = idaAuthenticatorImpl.doKycAuth("relyingId", "clientId", kycAuthDto);
+//
+// Assert.assertEquals(kycAuthResult.getKycToken(), kycAuthResult.getKycToken());
+// }
+//
+// @Test
+// public void doKycAuth_withAuthChallengeNull_thenFail() throws Exception {
+// KycAuthDto kycAuthDto = new KycAuthDto();
+// kycAuthDto.setIndividualId("IND1234");
+// kycAuthDto.setTransactionId("TRAN1234");
+// kycAuthDto.setChallengeList(null);
+//
+// Assert.assertThrows(KycAuthException.class,
+// () -> idaAuthenticatorImpl.doKycAuth("relyingId", "clientId", kycAuthDto));
+// }
+//
+// @Test
+// public void doKycAuth_withInvalidAuthChallenge_thenFail() throws Exception {
+// KycAuthDto kycAuthDto = new KycAuthDto();
+// kycAuthDto.setIndividualId("IND1234");
+// kycAuthDto.setTransactionId("TRAN1234");
+// AuthChallenge authChallenge = new AuthChallenge();
+// authChallenge.setAuthFactorType("Test");
+// authChallenge.setChallenge("111111");
+// List authChallengeList = new ArrayList<>();
+// authChallengeList.add(authChallenge);
+// kycAuthDto.setChallengeList(authChallengeList);
+//
+// Assert.assertThrows(KycAuthException.class,
+// () -> idaAuthenticatorImpl.doKycAuth("relyingId", "clientId", kycAuthDto));
+// }
+//
+// @Test
+// public void doKycAuth_withBIOAuthChallenge_thenPass() throws Exception {
+// KycAuthDto kycAuthDto = new KycAuthDto();
+// kycAuthDto.setIndividualId("IND1234");
+// kycAuthDto.setTransactionId("TRAN1234");
+// AuthChallenge authChallenge = new AuthChallenge();
+// authChallenge.setAuthFactorType("BIO");
+// authChallenge.setChallenge("111111");
+// List authChallengeList = new ArrayList<>();
+// authChallengeList.add(authChallenge);
+// kycAuthDto.setChallengeList(authChallengeList);
+//
+// Biometric b = new Biometric();
+// b.setData(
+// "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c");
+// b.setHash("Hash");
+// b.setSessionKey("SessionKey");
+// b.setSpecVersion("SepecV");
+// b.setThumbprint("Thumbprint");
+// List bioList = new ArrayList<>();
+// bioList.add(b);
+// Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+// IdaKycAuthResponse idaKycAuthResponse = new IdaKycAuthResponse();
+// idaKycAuthResponse.setAuthToken("authToken1234");
+// idaKycAuthResponse.setKycToken("kycToken1234");
+// idaKycAuthResponse.setKycStatus(true);
+//
+// IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+// idaResponseWrapper.setResponse(idaKycAuthResponse);
+// idaResponseWrapper.setTransactionID("TRAN123");
+// idaResponseWrapper.setVersion("VER1");
+//
+// ResponseEntity> responseEntity = new ResponseEntity>(
+// idaResponseWrapper, HttpStatus.OK);
+//
+// Mockito.when(restTemplate.exchange(Mockito.>any(),
+// Mockito.>>any()))
+// .thenReturn(responseEntity);
+//
+// KycAuthResult kycAuthResult = idaAuthenticatorImpl.doKycAuth("relyingId", "clientId", kycAuthDto);
+//
+// Assert.assertEquals(kycAuthResult.getKycToken(), kycAuthResult.getKycToken());
+// }
+
+ @Test
+ public void doKycExchange_withValidDetails_thenPass() throws Exception {
+ KycExchangeDto kycExchangeDto = new KycExchangeDto();
+ kycExchangeDto.setIndividualId("IND1234");
+ kycExchangeDto.setKycToken("KYCT123");
+ kycExchangeDto.setTransactionId("TRAN123");
+ List acceptedClaims = new ArrayList<>();
+ acceptedClaims.add("claims");
+ kycExchangeDto.setAcceptedClaims(acceptedClaims);
+ String[] claimsLacales = new String[] { "claims", "locales" };
+ kycExchangeDto.setClaimsLocales(claimsLacales);
+
+ Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+
+ IdaKycExchangeResponse idaKycExchangeResponse = new IdaKycExchangeResponse();
+ idaKycExchangeResponse.setEncryptedKyc("ENCRKYC123");
+
+ IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+ idaResponseWrapper.setResponse(idaKycExchangeResponse);
+ idaResponseWrapper.setTransactionID("TRAN123");
+ idaResponseWrapper.setVersion("VER1");
+
+ ResponseEntity> responseEntity = new ResponseEntity>(
+ idaResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(responseEntity);
+
+ KycExchangeResult kycExchangeResult = idaAuthenticatorImpl.doKycExchange("relyingPartyId", "clientId",
+ kycExchangeDto);
+
+ Assert.assertEquals(idaKycExchangeResponse.getEncryptedKyc(), kycExchangeResult.getEncryptedKyc());
+ }
+
+ @Test
+ public void doKycExchange_withInvalidDetails_thenFail() throws Exception {
+ KycExchangeDto kycExchangeDto = new KycExchangeDto();
+ kycExchangeDto.setIndividualId(null);
+ kycExchangeDto.setKycToken("KYCT123");
+ kycExchangeDto.setTransactionId("TRAN123");
+ List acceptedClaims = new ArrayList<>();
+ acceptedClaims.add("claims");
+ kycExchangeDto.setAcceptedClaims(acceptedClaims);
+ String[] claimsLacales = new String[] { "claims", "locales" };
+ kycExchangeDto.setClaimsLocales(claimsLacales);
+
+ Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+
+ IdaKycExchangeResponse idaKycExchangeResponse = new IdaKycExchangeResponse();
+ idaKycExchangeResponse.setEncryptedKyc("ENCRKYC123");
+
+ IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+ idaResponseWrapper.setResponse(null);
+ idaResponseWrapper.setTransactionID("TRAN123");
+ idaResponseWrapper.setVersion("VER1");
+
+ ResponseEntity> responseEntity = new ResponseEntity>(
+ idaResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(responseEntity);
+
+ Assert.assertThrows(KycExchangeException.class,
+ () -> idaAuthenticatorImpl.doKycExchange("test-relyingPartyId", "test-clientId", kycExchangeDto));
+ }
+
+ @Test
+ public void doKycExchange_withInvalidIndividualId_throwsException() throws KycExchangeException, Exception {
+ KycExchangeDto kycExchangeDto = new KycExchangeDto();
+ kycExchangeDto.setIndividualId("IND1234");
+ kycExchangeDto.setKycToken("KYCT123");
+ kycExchangeDto.setTransactionId("TRAN123");
+ List acceptedClaims = new ArrayList<>();
+ acceptedClaims.add("claims");
+ kycExchangeDto.setAcceptedClaims(acceptedClaims);
+ String[] claimsLacales = new String[] { "claims", "locales" };
+ kycExchangeDto.setClaimsLocales(claimsLacales);
+
+ Mockito.when(mapper.writeValueAsString(Mockito.any())).thenReturn("value");
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(null);
+
+ Assert.assertThrows(KycExchangeException.class,
+ () -> idaAuthenticatorImpl.doKycExchange("relyingId", "clientId", kycExchangeDto));
+ }
+
+ @Test
+ public void sendOtp_withValidDetails_thenPass() throws Exception {
+ SendOtpDto sendOtpDto = new SendOtpDto();
+ sendOtpDto.setIndividualId("1234");
+ sendOtpDto.setTransactionId("4567");
+ List otpChannelsList = new ArrayList<>();
+ otpChannelsList.add("channel");
+ sendOtpDto.setOtpChannels(otpChannelsList);
+
+ Mockito.when(helperService.sendOTP(any(),any(),any())).thenReturn(new SendOtpResult(sendOtpDto.getTransactionId(), "", ""));
+
+ SendOtpResult sendOtpResult = idaAuthenticatorImpl.sendOtp("rly123", "cli123", sendOtpDto);
+
+ Assert.assertEquals(sendOtpDto.getTransactionId(), sendOtpResult.getTransactionId());
+ }
+
+ @Test
+ public void sendOtp_withErrorResponse_throwsException() throws Exception {
+ SendOtpDto sendOtpDto = new SendOtpDto();
+ sendOtpDto.setIndividualId(null);
+ sendOtpDto.setTransactionId("4567");
+ List otpChannelsList = new ArrayList<>();
+ otpChannelsList.add("channel");
+ sendOtpDto.setOtpChannels(otpChannelsList);
+
+ Mockito.when(helperService.sendOTP(any(),any(),any())).thenThrow(new SendOtpException("error-100"));
+
+ try {
+ idaAuthenticatorImpl.sendOtp("rly123", "cli123", sendOtpDto);
+ Assert.fail();
+ } catch (SendOtpException e) {
+ Assert.assertEquals("error-100", e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void isSupportedOtpChannel_withInvalidChannel_thenFail() {
+ Assert.assertFalse(idaAuthenticatorImpl.isSupportedOtpChannel("test"));
+ }
+
+ @Test
+ public void isSupportedOtpChannel_withValidChannel_thenPass() {
+ Assert.assertTrue(idaAuthenticatorImpl.isSupportedOtpChannel("OTP"));
+ }
+
+ @Test
+ public void getAllKycSigningCertificates_withValidDetails_thenPass() throws Exception {
+ Mockito.when(authTransactionHelper.getAuthToken()).thenReturn("test-token");
+
+ GetAllCertificatesResponse getAllCertificatesResponse = new GetAllCertificatesResponse();
+ getAllCertificatesResponse.setAllCertificates(new ArrayList());
+
+ ResponseWrapper certsResponseWrapper = new ResponseWrapper();
+ certsResponseWrapper.setId("test-id");
+ certsResponseWrapper.setResponse(getAllCertificatesResponse);
+
+ ResponseEntity> certsResponseEntity = new ResponseEntity>(
+ certsResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(certsResponseEntity);
+
+ List signingCertificates = new ArrayList<>();
+
+ signingCertificates = idaAuthenticatorImpl.getAllKycSigningCertificates();
+
+ Assert.assertSame(signingCertificates, getAllCertificatesResponse.getAllCertificates());
+ }
+
+ @Test
+ public void getAllKycSigningCertificates_withInvalidResponse_throwsException() throws Exception {
+ Mockito.when(authTransactionHelper.getAuthToken()).thenReturn("test-token");
+
+ ResponseWrapper certsResponseWrapper = new ResponseWrapper();
+ certsResponseWrapper.setId("test-id");
+ List errors = new ArrayList<>();
+ ServiceError error = new ServiceError("ERR-001", "Certificates not found");
+ errors.add(error);
+ certsResponseWrapper.setErrors(errors);
+
+ ResponseEntity> certsResponseEntity = new ResponseEntity>(
+ certsResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(certsResponseEntity);
+
+ Assert.assertThrows(KycSigningCertificateException.class,
+ () -> idaAuthenticatorImpl.getAllKycSigningCertificates());
+ }
+
+ @Test
+ public void getAllKycSigningCertificates_withErrorResponse_throwsException() throws Exception {
+ Mockito.when(authTransactionHelper.getAuthToken()).thenReturn("test-token");
+
+ ResponseWrapper certsResponseWrapper = new ResponseWrapper();
+ certsResponseWrapper.setId("test-id");
+ List errors = new ArrayList<>();
+ ServiceError error = new ServiceError("ERR-001", "Certificates not found");
+ errors.add(error);
+ certsResponseWrapper.setErrors(errors);
+
+ ResponseEntity> certsResponseEntity = new ResponseEntity>(
+ certsResponseWrapper, HttpStatus.FORBIDDEN);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(certsResponseEntity);
+
+ Assert.assertThrows(KycSigningCertificateException.class,
+ () -> idaAuthenticatorImpl.getAllKycSigningCertificates());
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Test
+ public void getAllKycSigningCertificates_withInvalidToken_thenFail() throws Exception {
+ Mockito.when(authTransactionHelper.getAuthToken()).thenReturn("test-token");
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>any())).thenThrow(RuntimeException.class);
+
+ Assert.assertThrows(KycSigningCertificateException.class,
+ () -> idaAuthenticatorImpl.getAllKycSigningCertificates());
+ }
+
+}
diff --git a/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImplTest.java b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImplTest.java
new file mode 100644
index 00000000000..47d3d69d9dd
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/IdaKeyBinderImplTest.java
@@ -0,0 +1,188 @@
+package io.mosip.authentication.esignet.integration.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.mosip.authentication.esignet.integration.dto.*;
+import io.mosip.esignet.api.dto.KeyBindingResult;
+import io.mosip.esignet.api.dto.SendOtpDto;
+import io.mosip.esignet.api.dto.SendOtpResult;
+import io.mosip.esignet.api.exception.KeyBindingException;
+import io.mosip.esignet.api.exception.SendOtpException;
+import io.mosip.esignet.api.util.ErrorConstants;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.parameters.P;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.*;
+
+import static org.mockito.ArgumentMatchers.any;
+
+@RunWith(MockitoJUnitRunner.class)
+public class IdaKeyBinderImplTest {
+
+ @InjectMocks
+ private IdaKeyBinderImpl idaKeyBinderImpl;
+
+ @Mock
+ private HelperService helperService;
+
+ @Mock
+ private RestTemplate restTemplate;
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+ private static final String PARTNER_ID_HEADER = "partner-id";
+ private static final String PARTNER_API_KEY_HEADER = "partner-api-key";
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ ReflectionTestUtils.setField(idaKeyBinderImpl, "keyBinderUrl", "https://localhost/identity-key-binding/mispLK/");
+ ReflectionTestUtils.setField(idaKeyBinderImpl, "objectMapper", objectMapper);
+ }
+
+ @Test
+ public void sendBindingOtp_withValidDetails_thenPass() throws Exception {
+ SendOtpDto sendOtpDto = new SendOtpDto();
+ sendOtpDto.setIndividualId("1234");
+ sendOtpDto.setTransactionId("4567");
+ List otpChannelsList = new ArrayList<>();
+ otpChannelsList.add("channel");
+ sendOtpDto.setOtpChannels(otpChannelsList);
+ Map headers = new HashMap<>();
+ headers.put(PARTNER_ID_HEADER, PARTNER_ID_HEADER);
+ headers.put(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER);
+ Mockito.when(helperService.sendOTP(any(),any(),any())).thenReturn(new SendOtpResult(sendOtpDto.getTransactionId(), "", ""));
+ SendOtpResult sendOtpResult = idaKeyBinderImpl.sendBindingOtp("individualId", Arrays.asList("email"), headers);
+ Assert.assertEquals(sendOtpDto.getTransactionId(), sendOtpResult.getTransactionId());
+ }
+
+ @Test
+ public void sendBindingOtp_withErrorResponse_throwsException() throws Exception {
+ SendOtpDto sendOtpDto = new SendOtpDto();
+ sendOtpDto.setIndividualId(null);
+ sendOtpDto.setTransactionId("4567");
+ List otpChannelsList = new ArrayList<>();
+ otpChannelsList.add("channel");
+ sendOtpDto.setOtpChannels(otpChannelsList);
+ Mockito.when(helperService.sendOTP(any(),any(),any())).thenThrow(new SendOtpException("error-100"));
+ Map headers = new HashMap<>();
+ headers.put(PARTNER_ID_HEADER, PARTNER_ID_HEADER);
+ headers.put(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER);
+ try {
+ idaKeyBinderImpl.sendBindingOtp("individualId", Arrays.asList("email"), headers);
+ Assert.fail();
+ } catch (SendOtpException e) {
+ Assert.assertEquals("error-100", e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void sendBindingOtp_withEmptyHeaders_throwsException() throws Exception {
+ try {
+ idaKeyBinderImpl.sendBindingOtp("individualId", Arrays.asList("email"), new HashMap<>());
+ Assert.fail();
+ } catch (SendOtpException e) {
+ Assert.assertEquals(IdaKeyBinderImpl.REQUIRED_HEADERS_MISSING, e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void doKeyBinding_withValidDetails_thenPass() throws KeyBindingException {
+ IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+ KeyBindingResponse keyBindingResponse = new KeyBindingResponse();
+ keyBindingResponse.setAuthToken("auth-token");
+ keyBindingResponse.setBindingAuthStatus(true);
+ keyBindingResponse.setIdentityCertificate("certificate");
+ idaResponseWrapper.setResponse(keyBindingResponse);
+ ResponseEntity> responseEntity = new ResponseEntity>(
+ idaResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(responseEntity);
+
+ Map headers = new HashMap<>();
+ headers.put(PARTNER_ID_HEADER, PARTNER_ID_HEADER);
+ headers.put(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER);
+ KeyBindingResult keyBindingResult = idaKeyBinderImpl.doKeyBinding("individualId", new ArrayList<>(), new HashMap<>(),
+ "WLA", headers);
+ Assert.assertNotNull(keyBindingResult);
+ Assert.assertEquals(keyBindingResponse.getAuthToken(), keyBindingResult.getPartnerSpecificUserToken());
+ Assert.assertEquals(keyBindingResponse.getIdentityCertificate(), keyBindingResult.getCertificate());
+ }
+
+ @Test
+ public void doKeyBinding_withAuthFailure_thenPass() {
+ IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+ KeyBindingResponse keyBindingResponse = new KeyBindingResponse();
+ keyBindingResponse.setAuthToken("auth-token");
+ keyBindingResponse.setBindingAuthStatus(false);
+ keyBindingResponse.setIdentityCertificate("certificate");
+ idaResponseWrapper.setResponse(keyBindingResponse);
+ ResponseEntity> responseEntity = new ResponseEntity>(
+ idaResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(responseEntity);
+
+ Map headers = new HashMap<>();
+ headers.put(PARTNER_ID_HEADER, PARTNER_ID_HEADER);
+ headers.put(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER);
+ try {
+ idaKeyBinderImpl.doKeyBinding("individualId", new ArrayList<>(), new HashMap<>(),
+ "WLA", headers);
+ Assert.fail();
+ } catch (KeyBindingException e) {
+ Assert.assertEquals(ErrorConstants.BINDING_AUTH_FAILED, e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void doKeyBinding_withErrorResponse_thenFail() {
+ IdaResponseWrapper idaResponseWrapper = new IdaResponseWrapper<>();
+ IdaError idaError = new IdaError();
+ idaError.setErrorCode("test-err-code");
+ idaResponseWrapper.setErrors(Arrays.asList(idaError));
+ ResponseEntity> responseEntity = new ResponseEntity>(
+ idaResponseWrapper, HttpStatus.OK);
+
+ Mockito.when(restTemplate.exchange(Mockito.>any(),
+ Mockito.>>any()))
+ .thenReturn(responseEntity);
+
+ Map headers = new HashMap<>();
+ headers.put(PARTNER_ID_HEADER, PARTNER_ID_HEADER);
+ headers.put(PARTNER_API_KEY_HEADER, PARTNER_API_KEY_HEADER);
+ try {
+ idaKeyBinderImpl.doKeyBinding("individualId", new ArrayList<>(), new HashMap<>(),
+ "WLA", headers);
+ Assert.fail();
+ } catch (KeyBindingException e) {
+ Assert.assertEquals("test-err-code", e.getErrorCode());
+ }
+ }
+
+ @Test
+ public void doKeyBinding_withEmptyHeaders_thenFail() {
+ try {
+ idaKeyBinderImpl.doKeyBinding("individualId", new ArrayList<>(), new HashMap<>(),
+ "WLA", new HashMap<>());
+ Assert.fail();
+ } catch (KeyBindingException e) {
+ Assert.assertEquals(IdaKeyBinderImpl.REQUIRED_HEADERS_MISSING, e.getErrorCode());
+ }
+ }
+}
diff --git a/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/TestUtil.java b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/TestUtil.java
new file mode 100644
index 00000000000..1ebb8ad2600
--- /dev/null
+++ b/authentication/esignet-integration-impl/src/test/java/io/mosip/authentication/esignet/integration/service/TestUtil.java
@@ -0,0 +1,80 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/.
+ */
+package io.mosip.authentication.esignet.integration.service;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import java.util.UUID;
+
+
+import com.nimbusds.jose.jwk.Curve;
+import com.nimbusds.jose.jwk.ECKey;
+import com.nimbusds.jose.jwk.JWK;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import javax.security.auth.x500.X500Principal;
+
+@Slf4j
+public class TestUtil {
+
+ public static JWK generateJWK_RSA() {
+ // Generate the RSA key pair
+ try {
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
+ gen.initialize(2048);
+ KeyPair keyPair = gen.generateKeyPair();
+ // Convert public key to JWK format
+ return new RSAKey.Builder((RSAPublicKey)keyPair.getPublic())
+ .privateKey((RSAPrivateKey)keyPair.getPrivate())
+ .keyUse(KeyUse.SIGNATURE)
+ .keyID(UUID.randomUUID().toString())
+ .build();
+ } catch (NoSuchAlgorithmException e) {
+ log.error("generateJWK_RSA failed", e);
+ }
+ return null;
+ }
+
+ public static X509Certificate getCertificate() throws Exception {
+ JWK clientJWK = TestUtil.generateJWK_RSA();
+ X509V3CertificateGenerator generator = new X509V3CertificateGenerator();
+ X500Principal dnName = new X500Principal("CN=Test");
+ generator.setSubjectDN(dnName);
+ generator.setIssuerDN(dnName); // use the same
+ generator.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
+ generator.setNotAfter(new Date(System.currentTimeMillis() + 24 * 365 * 24 * 60 * 60 * 1000));
+ generator.setPublicKey(clientJWK.toRSAKey().toPublicKey());
+ generator.setSignatureAlgorithm("SHA256WITHRSA");
+ generator.setSerialNumber(new BigInteger(String.valueOf(System.currentTimeMillis())));
+ return generator.generate(clientJWK.toRSAKey().toPrivateKey());
+ }
+
+ public static X509Certificate getExpiredCertificate() throws Exception {
+ JWK clientJWK = TestUtil.generateJWK_RSA();
+ X509V3CertificateGenerator generator = new X509V3CertificateGenerator();
+ X500Principal dnName = new X500Principal("CN=Test");
+ generator.setSubjectDN(dnName);
+ generator.setIssuerDN(dnName); // use the same
+ generator.setNotBefore(new Date(System.currentTimeMillis()));
+ generator.setNotAfter(new Date(System.currentTimeMillis()));
+ generator.setPublicKey(clientJWK.toRSAKey().toPublicKey());
+ generator.setSignatureAlgorithm("SHA256WITHRSA");
+ generator.setSerialNumber(new BigInteger(String.valueOf(System.currentTimeMillis())));
+ return generator.generate(clientJWK.toRSAKey().toPrivateKey());
+ }
+}
diff --git a/authentication/pom.xml b/authentication/pom.xml
index 51705ab9395..0200e7fbd4e 100644
--- a/authentication/pom.xml
+++ b/authentication/pom.xml
@@ -64,6 +64,7 @@
authentication-internal-service
authentication-kyc-service
authentication-otp-service
+ esignet-integration-impl
@@ -113,7 +114,7 @@
1.18.8
- 2.0.2.RELEASE
+ 2.3.6.RELEASE
4.0.1.RELEASE
5.0.5.RELEASE
2.0.0.RELEASE