All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mosip.registration.mdm.service.impl.MosipDeviceSpecificationHelper Maven / Gradle / Ivy

package io.mosip.registration.mdm.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.mosip.kernel.core.exception.ExceptionUtils;
import io.mosip.kernel.core.logger.spi.Logger;
import io.mosip.kernel.core.util.CryptoUtil;
import io.mosip.kernel.core.util.DateUtils;
import io.mosip.kernel.signature.constant.SignatureConstant;
import io.mosip.kernel.signature.dto.JWTSignatureVerifyRequestDto;
import io.mosip.kernel.signature.dto.JWTSignatureVerifyResponseDto;
import io.mosip.kernel.signature.service.SignatureService;
import io.mosip.registration.config.AppConfig;
import io.mosip.registration.constants.RegistrationConstants;
import io.mosip.registration.context.ApplicationContext;
import io.mosip.registration.exception.DeviceException;
import io.mosip.registration.exception.RegBaseCheckedException;
import io.mosip.registration.exception.RegistrationExceptionConstants;
import io.mosip.registration.mdm.dto.DeviceInfo;
import io.mosip.registration.mdm.dto.MDMError;
import io.mosip.registration.mdm.dto.MdmDeviceInfo;
import io.mosip.registration.mdm.sbi.spec_1_0.dto.response.MdmSbiDeviceInfoWrapper;

import org.apache.http.Consts;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static io.mosip.registration.constants.RegistrationConstants.APPLICATION_ID;
import static io.mosip.registration.constants.RegistrationConstants.APPLICATION_NAME;

/**
 * All helper methods commons to spec implementations
 *
 * @author anusha
 */
@Component
public class MosipDeviceSpecificationHelper {

	private static final Logger LOGGER = AppConfig.getLogger(MosipDeviceSpecificationHelper.class);
	private static final String MDM_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";

	private ObjectMapper mapper = new ObjectMapper();

	@Autowired
	private SignatureService signatureService;

	@Value("${mosip.registration.mdm.trust.domain.rcapture:DEVICE}")
	private String rCaptureTrustDomain;

	@Value("${mosip.registration.mdm.trust.domain.digitalId:DEVICE}")
	private String digitalIdTrustDomain;

	@Value("${mosip.registration.mdm.trust.domain.deviceinfo:DEVICE}")
	private String deviceInfoTrustDomain;

	private final String CONTENT_LENGTH = "Content-Length:";

	public String getPayLoad(String data) throws RegBaseCheckedException {
		if (data == null || data.isEmpty()) {
			throw new RegBaseCheckedException(RegistrationExceptionConstants.MDS_JWT_INVALID.getErrorCode(),
					RegistrationExceptionConstants.MDS_JWT_INVALID.getErrorMessage());
		}
		Pattern pattern = Pattern.compile(RegistrationConstants.BIOMETRIC_SEPERATOR);
		Matcher matcher = pattern.matcher(data);
		if (matcher.find()) {
			return matcher.group(1);
		}
		throw new RegBaseCheckedException(RegistrationExceptionConstants.MDS_PAYLOAD_EMPTY.getErrorCode(),
				RegistrationExceptionConstants.MDS_PAYLOAD_EMPTY.getErrorMessage());
	}
	
	public String getSignature(String data) throws RegBaseCheckedException {
		if (data == null || data.isEmpty()) {
			throw new RegBaseCheckedException(RegistrationExceptionConstants.MDS_JWT_INVALID.getErrorCode(),
					RegistrationExceptionConstants.MDS_JWT_INVALID.getErrorMessage());
		}
		Pattern pattern = Pattern.compile(RegistrationConstants.BIOMETRIC_SEPERATOR);
		Matcher matcher = pattern.matcher(data);
		if(matcher.find()) {
			//returns header..signature
			return data.replace(matcher.group(1),"");
		}

		throw new RegBaseCheckedException(RegistrationExceptionConstants.MDS_SIGNATURE_EMPTY.getErrorCode(),
				RegistrationExceptionConstants.MDS_SIGNATURE_EMPTY.getErrorMessage());
	}

	public DeviceInfo getDeviceInfoDecoded(String deviceInfo, Class classType) {
		try {
			validateJWTResponse(deviceInfo, deviceInfoTrustDomain);
			String result = new String(CryptoUtil.decodeURLSafeBase64(getPayLoad(deviceInfo)));
			if(classType.getName().equals("io.mosip.registration.mdm.sbi.spec_1_0.service.impl.MosipDeviceSpecification_SBI_1_0_ProviderImpl")) {
				return mapper.readValue(result, MdmSbiDeviceInfoWrapper.class);
			} else {
				return mapper.readValue(result, MdmDeviceInfo.class);
			}
			
		} catch (Exception exception) {
			LOGGER.error(APPLICATION_ID, APPLICATION_NAME, "Failed to decode device info",
					ExceptionUtils.getStackTrace(exception));
		}
		return null;
	}

	public void validateJWTResponse(final String signedData, final String domain) throws DeviceException {
		JWTSignatureVerifyRequestDto jwtSignatureVerifyRequestDto = new JWTSignatureVerifyRequestDto();
		jwtSignatureVerifyRequestDto.setValidateTrust(true);
		jwtSignatureVerifyRequestDto.setDomain(domain);
		jwtSignatureVerifyRequestDto.setJwtSignatureData(signedData);
		
		JWTSignatureVerifyResponseDto jwtSignatureVerifyResponseDto = signatureService.jwtVerify(jwtSignatureVerifyRequestDto);
		if(!jwtSignatureVerifyResponseDto.isSignatureValid())
				throw new DeviceException(MDMError.MDM_INVALID_SIGNATURE.getErrorCode(), MDMError.MDM_INVALID_SIGNATURE.getErrorMessage());
		
		if (jwtSignatureVerifyRequestDto.getValidateTrust() && !jwtSignatureVerifyResponseDto.getTrustValid().equals(SignatureConstant.TRUST_VALID)) {
		      throw new DeviceException(MDMError.MDM_CERT_PATH_TRUST_FAILED.getErrorCode(), MDMError.MDM_CERT_PATH_TRUST_FAILED.getErrorMessage());
		}
	}

	public String generateMDMTransactionId() {
		return UUID.randomUUID().toString();
	}

	public String buildUrl(int port, String endPoint) {
		return String.format("%s:%s/%s", getRunningurl(), port, endPoint);
	}

	private String getRunningurl() {
		return "http://127.0.0.1";
	}

	public ObjectMapper getMapper() {
		return mapper;
	}

	/**
	 * Using the urlStream get the next JPEG image as a byte[]
	 *
	 * @return byte[] of the JPEG
	 * @throws IOException
	 * @throws RegBaseCheckedException
	 */
	public byte[] getJPEGByteArray(InputStream urlStream, long maxTimeLimit)
			throws IOException, RegBaseCheckedException {

		int currByte = -1;

		boolean captureContentLength = false;
		StringWriter contentLengthStringWriter = new StringWriter(128);
		StringWriter headerWriter = new StringWriter(128);

		int contentLength = 0;

		while ((currByte = urlStream.read()) > -1) {
			if (captureContentLength) {
				if (currByte == 10 || currByte == 13) {
					contentLength = Integer.parseInt(contentLengthStringWriter.toString().replace(" ", ""));
					break;
				}
				contentLengthStringWriter.write(currByte);

			} else {
				headerWriter.write(currByte);
				String tempString = headerWriter.toString();
				int indexOf = tempString.indexOf(CONTENT_LENGTH);
				if (indexOf > 0) {
					captureContentLength = true;
				}
			}
			timeOutCheck(maxTimeLimit);
		}

		// 255 indicates the start of the jpeg image
		while (urlStream.read() != 255) {

			timeOutCheck(maxTimeLimit);
		}

		// rest is the buffer
		byte[] imageBytes = new byte[contentLength + 1];
		// since we ate the original 255 , shove it back in
		imageBytes[0] = (byte) 255;
		int offset = 1;
		int numRead = 0;
		while (offset < imageBytes.length
				&& (numRead = urlStream.read(imageBytes, offset, imageBytes.length - offset)) >= 0) {
			timeOutCheck(maxTimeLimit);
			offset += numRead;
		}

		return imageBytes;
	}

	private void timeOutCheck(long maxTimeLimit) throws RegBaseCheckedException {

		if (System.currentTimeMillis() > maxTimeLimit) {

			throw new RegBaseCheckedException(RegistrationExceptionConstants.MDS_STREAM_TIMEOUT.getErrorCode(),
					RegistrationExceptionConstants.MDS_STREAM_TIMEOUT.getErrorMessage());
		}
	}
	
	public void validateResponseTimestamp(String responseTime) throws RegBaseCheckedException {
		if(responseTime != null) {
			LocalDateTime ts = DateUtils.parseUTCToLocalDateTime(responseTime, MDM_DATETIME_PATTERN);
			//LocalDateTime ts = DateUtils.convertUTCToLocalDateTime(responseTime);
			if(ts.isAfter(LocalDateTime.now().minusMinutes(getAllowedLagInMinutes()))
					&& ts.isBefore(LocalDateTime.now().plusMinutes(getAllowedLagInMinutes())))
				return;
		}

		throw new RegBaseCheckedException(
				RegistrationExceptionConstants.MDS_CAPTURE_INVALID_TIME.getErrorCode(),
				RegistrationExceptionConstants.MDS_CAPTURE_INVALID_TIME.getErrorMessage());
	}

	private int getAllowedLagInMinutes() {
		return Integer.parseInt((String) ApplicationContext.map()
				.getOrDefault(RegistrationConstants.MDS_RESP_ALLOWED_LAG_MINS, "5"));
	}
	
	
	public void validateQualityScore(String qualityScore) throws RegBaseCheckedException {
		if (qualityScore == null || qualityScore.isEmpty()) {
			throw new RegBaseCheckedException(
					RegistrationExceptionConstants.MDS_RCAPTURE_ERROR.getErrorCode(),
					RegistrationExceptionConstants.MDS_RCAPTURE_ERROR.getErrorMessage()
							+ " Identified Quality Score for capture biometrics is null or Empty");
		}
	}

	public static int getMDMConnectionTimeout(String method) {
		Integer timeout = ApplicationContext.getIntValueFromApplicationMap(
				String.format(RegistrationConstants.METHOD_BASED_MDM_CONNECTION_TIMEOUT, method.toUpperCase()));
		if(timeout == null || timeout == 0) {
			timeout = ApplicationContext.getIntValueFromApplicationMap(RegistrationConstants.MDM_CONNECTION_TIMEOUT);
		}
		return (timeout == null || timeout == 0) ? 10000 : timeout;
	}

	public String getHttpClientResponseEntity(String url, String method, String body) throws IOException {
		int timeout = getMDMConnectionTimeout(method);
		LOGGER.debug("MDM HTTP CALL method : {}  with timeout {}", method, timeout);
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectTimeout(timeout)
				.setSocketTimeout(timeout)
				.setConnectionRequestTimeout(timeout)
				.build();
		try (CloseableHttpClient client = HttpClients.createDefault()) {
			StringEntity requestEntity = new StringEntity(body, ContentType.create("Content-Type", Consts.UTF_8));
			HttpUriRequest httpUriRequest = RequestBuilder.create(method)
					.setConfig(requestConfig)
					.setUri(url)
					.setEntity(requestEntity)
					.build();
			CloseableHttpResponse response = client.execute(httpUriRequest);
			return EntityUtils.toString(response.getEntity());
		}
	}
	
	public CloseableHttpResponse getHttpClientResponse(String url, String method, String body) throws IOException {
		int timeout = getMDMConnectionTimeout(method);
		LOGGER.debug("MDM HTTP CALL method : {}  with timeout {}", method, timeout);
		RequestConfig requestConfig = RequestConfig.custom()
				.setConnectTimeout(timeout)
				.setSocketTimeout(timeout)
				.setConnectionRequestTimeout(timeout)
				.build();
		CloseableHttpClient client = HttpClients.createDefault();
		StringEntity requestEntity = new StringEntity(body, ContentType.create("Content-Type", Consts.UTF_8));
		HttpUriRequest httpUriRequest = RequestBuilder.create(method)
				.setConfig(requestConfig)
				.setUri(url)
				.setEntity(requestEntity)
				.build();
		return client.execute(httpUriRequest);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy