Skip to content
CertificateProcessor.java 4.87 KiB
Newer Older
package org.astrogrid.security.delegation;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ca.nrc.cadc.auth.SSLUtil;
import org.apache.log4j.Logger;

/**
 * 
 * @author Guy Rixon
 */
public class CertificateProcessor extends ResourceProcessor
{

    private static final Logger log = Logger.getLogger(CertificateProcessor.class);

    /**
     * Responds to HTTP requests.
     */
    @Override
    public void service(HttpServletRequest request, DelegationUri path,
            HttpServletResponse response) throws IOException
    {
        if (request.getMethod().equals("GET"))
        {
            sendCertificate(path.getUser(), response);
        }
        else if (request.getMethod().equals("PUT"))
        {
            receiveCertificate(request, path.getUser(), response);
        }
        else
        {
            response.setHeader("Accept", "GET");
            response.sendError(response.SC_METHOD_NOT_ALLOWED);
        }
    }

    /**
     * Writes to the client the X.509 certificate for an identity.
     */
    private void sendCertificate(String hashKey,
            HttpServletResponse response) throws IOException
    {
        if (Delegations.getInstance().hasCertificate(hashKey))
        {
            response.setContentType("text/plain");
            Delegations.getInstance().writeCertificate(hashKey,
                    response.getWriter());
        }
        else
        {
            response.sendError(response.SC_NOT_FOUND);
        }
    }

    /**
     * Receives an uploaded identity certificate. The certificate becomes
     * the content for they identity's /certificate resource.
     */
    private void receiveCertificate(HttpServletRequest request,
            String hashKey, HttpServletResponse response)
            throws IOException
    {
        if (Delegations.getInstance().isKnown(hashKey))
        {
            try
            {
                // the Certificate factory is quite fragile when it comes to
                // reading the PEM string. So we consume the stream, and 
                // extracts just the Certificates information from the 
                // stream by calling SSLUtil.getCertificates() and fed
                // it to the CertificateFactory
               
                int bytesRead = 0;
                int bytesToRead = 10000; // max size accepted for the input
                                         // stream
                byte[] input = new byte[bytesToRead];
                while (bytesRead < bytesToRead)
                {
                    int result = request.getInputStream().read(input,
                            bytesRead, bytesToRead - bytesRead);
                    if (result == -1)
                    {
                        break;
                    }
                    bytesRead += result;
                }
                
                if(bytesRead == bytesToRead)
                {
                    throw new 
                    CertificateException("Certificate to read too large (>" + 
                            bytesToRead + " bytes)");
                }

                byte[] code = SSLUtil.getCertificates(input);
                

                CertificateFactory factory = CertificateFactory
                .getInstance("X509");
                BufferedInputStream istream = new BufferedInputStream(
                        new ByteArrayInputStream(code));
                Collection certificates = 
                    factory.generateCertificates(istream);
                //certificate.checkValidity(); ???
                
                try
                {
                    X509Certificate[] certsArray = new X509Certificate[certificates.size()];
                    Delegations.getInstance().setCertificates(hashKey,
                            (X509Certificate[])certificates.toArray(certsArray));
                }
                catch (InvalidKeyException ex)
                {
                    throw new RuntimeException(ex);
                }
                log.info("Received a certificate for "
                        + ((X509Certificate) certificates.iterator()
                                .next()).getSubjectX500Principal() + " ("
                        + hashKey + ").");
            }
            catch (CertificateException ex)
            {
                System.out.println(ex);
                response.sendError(response.SC_BAD_REQUEST,
                        "Failed to parse the certificate: " + ex);
            }
        }
        else
        {
            response.sendError(response.SC_NOT_FOUND);
        }
    }

}