package org.apereo.cas.support.x509.rest;

import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.adaptors.x509.authentication.principal.X509CertificateCredential;
import org.apereo.cas.adaptors.x509.util.CertUtils;
import org.apereo.cas.authentication.Credential;
import org.apereo.cas.support.rest.DefaultCredentialFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.InputStreamSource;
import org.springframework.util.MultiValueMap;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.cert.X509Certificate;

/**
 * This is {@link X509CredentialFactory} that attempts to read the contents
 * of the request body under {@link #CERTIFICATE} parameter to locate and construct
 * X509 credentials. If the request body does not contain a certificate,
 * it will then fallback onto the default behavior of capturing credentials.
 *
 * @author Dmytro Fedonin
 * @since 5.1.0
 */
public class X509CredentialFactory extends DefaultCredentialFactory {
    private static final Logger LOGGER = LoggerFactory.getLogger(X509CredentialFactory.class);
    private static final String CERTIFICATE = "cert";

    @Override
    public Credential fromRequestBody(final MultiValueMap<String, String> requestBody) {
        final String cert = requestBody.getFirst(CERTIFICATE);
        LOGGER.debug("Certificate in the request body: [{}]", cert);
        if (StringUtils.isBlank(cert)) {
            return super.fromRequestBody(requestBody);
        }
        final InputStream is = new ByteArrayInputStream(cert.getBytes());
        final InputStreamSource iso = new InputStreamResource(is);
        final X509Certificate certificate = CertUtils.readCertificate(iso);
        final X509CertificateCredential credential = new X509CertificateCredential(new X509Certificate[]{certificate});
        credential.setCertificate(certificate);
        return credential;
    }
}
