KamuSMXmlDepoOnlineResolver.java

package io.mersel.dss.signer.api.services;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import eu.europa.esig.dss.model.x509.CertificateToken;

/**
 * KamuSM XML Deposu Online Resolver
 * İnternet üzerinden KamuSM sertifika deposunu indirir ve yönetir.
 * http://depo.kamusm.gov.tr/depo/SertifikaDeposu.xml
 */
@Service("kamuSMXmlDepoOnlineResolver")
public class KamuSMXmlDepoOnlineResolver extends AbstractKamuSMXmlDepoResolver {

    private static final String DEFAULT_URL = "http://depo.kamusm.gov.tr/depo/SertifikaDeposu.xml";
    
    private final RestTemplate restTemplate;
    private final ResourceLoader resourceLoader;
    private final String rootUrl;

    public KamuSMXmlDepoOnlineResolver(RestTemplateBuilder restTemplateBuilder,
                                        ResourceLoader resourceLoader,
                                        @Value("${kamusm.root.url:" + DEFAULT_URL + "}") String rootUrl) {
        this.restTemplate = restTemplateBuilder
                .setReadTimeout(Duration.ofSeconds(10))
                .setConnectTimeout(Duration.ofSeconds(5))
                .build();
        this.resourceLoader = resourceLoader;
        this.rootUrl = rootUrl;
    }

    @Override
    public void refreshTrustedRoots() {
        // Mevcut sertifikaları sakla (başarısız olursa geri yüklemek için)
        List<X509Certificate> previousRoots = new ArrayList<>(trustedRoots.get());
        List<CertificateToken> previousTokens = new ArrayList<>(trustedRootTokens.get());
        
        try {
            logger.info("KamuSM XML deposu online olarak yenileniyor: {}", rootUrl);
            String xmlBody = loadRepositoryXml();
            if (xmlBody == null || xmlBody.trim().isEmpty()) {
                logger.warn("KamuSM kok sertifika verisi bos - mevcut liste korunuyor");
                return;
            }
            List<X509Certificate> certificates = parseCertificates(xmlBody);
            if (certificates.isEmpty()) {
                logger.warn("KamuSM kok sertifika listesi bos - mevcut liste korunuyor");
                return;
            }
            List<CertificateToken> tokens = new ArrayList<CertificateToken>(certificates.size());
            for (X509Certificate certificate : certificates) {
                tokens.add(new CertificateToken(certificate));
            }
            trustedRoots.set(Collections.unmodifiableList(certificates));
            trustedRootTokens.set(Collections.unmodifiableList(tokens));
            logger.info("KamuSM kok sertifikalari basariyla yenilendi ({} adet)", certificates.size());
            
            // Trusted certificate source'u da guncelle
            updateTrustedCertificateSource();
            
        } catch (Exception ex) {
            logger.warn("KamuSM kok sertifikalarini yenileme basarisiz: {} - mevcut liste korunuyor", ex.getMessage());
            logger.debug("Kok sertifika yenileme hata detayi", ex);
            
            // Başarısız olursa önceki sertifikaları geri yükle
            if (!previousRoots.isEmpty()) {
                trustedRoots.set(Collections.unmodifiableList(previousRoots));
                trustedRootTokens.set(Collections.unmodifiableList(previousTokens));
                logger.info("Onceki sertifikalar geri yuklendi ({} adet)", previousRoots.size());
            }
        }
    }

    @Override
    protected String loadRepositoryXml() throws Exception {
        if (rootUrl.startsWith("classpath:") || rootUrl.startsWith("file:")) {
            Resource resource = resourceLoader.getResource(rootUrl);
            if (!resource.exists()) {
                throw new IllegalStateException("Resource not found: " + rootUrl);
            }
            try (InputStream inputStream = resource.getInputStream()) {
                byte[] bytes = IOUtils.toByteArray(inputStream);
                return new String(bytes, StandardCharsets.UTF_8);
            }
        }
        ResponseEntity<String> response = restTemplate.getForEntity(rootUrl, String.class);
        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            logger.warn("KamuSM kok sertifika indirme basarisiz. HTTP durum: {}", response.getStatusCode());
            return null;
        }
        return response.getBody();
    }
}