TubitakTimestampDataLoader.java
package io.mersel.dss.signer.api.services.timestamp.tubitak;
import eu.europa.esig.dss.service.http.commons.TimestampDataLoader;
import org.bouncycastle.asn1.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* TÜBİTAK ESYA Zaman Damgası servisi için özelleştirilmiş DataLoader.
* <p>
* Timestamp request'lerine TÜBİTAK'ın gerektirdiği kimlik doğrulama
* bilgilerini otomatik olarak ekler.
*/
public class TubitakTimestampDataLoader extends TimestampDataLoader {
private static final Logger LOGGER = LoggerFactory.getLogger(TubitakTimestampDataLoader.class);
private static final String IDENTITY_HEADER = "identity";
private static final String USER_AGENT_HEADER = "User-Agent";
private static final String TUBITAK_USER_AGENT = "UEKAE TSS Client";
private final int customerId;
private final String customerPassword;
/**
* TÜBİTAK timestamp data loader oluşturur.
*
* @param customerId Müşteri numarası
* @param customerPassword Müşteri parolası
*/
public TubitakTimestampDataLoader(int customerId, String customerPassword) {
super();
this.customerId = customerId;
this.customerPassword = customerPassword;
LOGGER.info("TÜBİTAK Timestamp DataLoader oluşturuldu. Müşteri ID: {}", customerId);
}
@Override
public byte[] post(String url, byte[] content) {
try {
byte[] dataHash = extractHashFromTimeStampRequest(content);
if (dataHash != null) {
String authToken = TubitakAuthenticationHelper.encryptIdentity(
customerId,
customerPassword,
dataHash
);
Map<String, String> headers = new HashMap<>();
headers.put(IDENTITY_HEADER, authToken);
headers.put(USER_AGENT_HEADER, TUBITAK_USER_AGENT);
LOGGER.debug("TÜBİTAK kimlik doğrulama eklendi. URL: {}", url);
return postWithHeaders(url, content, headers);
} else {
LOGGER.warn("TimeStamp request parse edilemedi, standart POST yapılıyor");
return super.post(url, content);
}
} catch (Exception e) {
LOGGER.error("TÜBİTAK kimlik doğrulama hatası: {}", e.getMessage());
LOGGER.debug("Hata detayı", e);
throw new RuntimeException("TÜBİTAK timestamp request başarısız", e);
}
}
/**
* Özel header'lar ile HTTP POST isteği gönderir.
*/
private byte[] postWithHeaders(String url, byte[] content, Map<String, String> customHeaders) {
try {
org.apache.http.client.methods.HttpPost httpPost =
new org.apache.http.client.methods.HttpPost(url);
httpPost.setHeader("Content-Type", "application/timestamp-query");
httpPost.setHeader("Accept", "application/timestamp-reply");
for (Map.Entry<String, String> entry : customHeaders.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
httpPost.setEntity(new org.apache.http.entity.ByteArrayEntity(content));
org.apache.http.impl.client.CloseableHttpClient httpClient =
org.apache.http.impl.client.HttpClients.createDefault();
try (org.apache.http.client.methods.CloseableHttpResponse response =
httpClient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
LOGGER.debug("HTTP response status: {}", statusCode);
if (statusCode != 200) {
throw new RuntimeException("HTTP error: " + statusCode);
}
return org.apache.http.util.EntityUtils.toByteArray(
response.getEntity());
} finally {
httpClient.close();
}
} catch (Exception e) {
LOGGER.error("HTTP request hatası: {}", e.getMessage());
throw new RuntimeException("Timestamp HTTP request başarısız", e);
}
}
/**
* Timestamp request'inden hash değerini çıkarır.
*/
private byte[] extractHashFromTimeStampRequest(byte[] tsReq) {
try {
ASN1InputStream asn1Stream = new ASN1InputStream(new ByteArrayInputStream(tsReq));
ASN1Primitive obj = asn1Stream.readObject();
asn1Stream.close();
if (!(obj instanceof ASN1Sequence)) {
return null;
}
ASN1Sequence tsReqSeq = (ASN1Sequence) obj;
if (tsReqSeq.size() < 2) {
return null;
}
ASN1Encodable messageImprintObj = tsReqSeq.getObjectAt(1);
if (!(messageImprintObj instanceof ASN1Sequence)) {
return null;
}
ASN1Sequence messageImprint = (ASN1Sequence) messageImprintObj;
if (messageImprint.size() < 2) {
return null;
}
ASN1Encodable hashedMessageObj = messageImprint.getObjectAt(1);
if (!(hashedMessageObj instanceof ASN1OctetString)) {
return null;
}
ASN1OctetString hashedMessage = (ASN1OctetString) hashedMessageObj;
byte[] hash = hashedMessage.getOctets();
LOGGER.debug("Timestamp request hash çıkarıldı. Uzunluk: {} bytes", hash.length);
return hash;
} catch (IOException e) {
LOGGER.warn("Timestamp request parse hatası: {}", e.getMessage());
return null;
}
}
}