Java tutorial
/* * eID Trust Service Project. * Copyright (C) 2009-2010 FedICT. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version * 3.0 as published by the Free Software Foundation. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, see * http://www.gnu.org/licenses/. */ package test.integ.be.fedict.performance; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.security.KeyPair; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServlet; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.bouncycastle.openssl.PEMReader; import org.mortbay.jetty.Connector; import org.mortbay.jetty.LocalConnector; import org.mortbay.jetty.Server; import org.mortbay.jetty.bio.SocketConnector; import org.mortbay.jetty.security.SecurityHandler; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHolder; import org.mortbay.jetty.servlet.ServletMapping; import org.mortbay.jetty.servlet.SessionHandler; import test.integ.be.fedict.performance.servlet.CertificateServlet; import test.integ.be.fedict.performance.servlet.ConfigurationServlet; import test.integ.be.fedict.performance.servlet.CrlServlet; import test.integ.be.fedict.performance.servlet.OcspServlet; import test.integ.be.fedict.performance.servlet.PrivateKeyServlet; /** * Test PKI which can be used by the trust service. * <p/> * {@link #start(String)} will start a jetty servlet server which publishes: * <ul> * <li>{@link ConfigurationServlet} to view/edit the PKI setup * <li>{@link CrlServlet} to download the CRL for specified CA * <li>{@link OcspServlet} for OCSP request for specified CA * <li>{@link CertificateServlet} to download the specified CA's certificate * <li>{@link PrivateKeyServlet} to download the specified CA's private key in * PEM format. * </ul> */ public class TestPKI { private static final Log LOG = LogFactory.getLog(TestPKI.class); private static TestPKI testPKI; // Jetty configuration private String host; private Server server; private String path; private List<String> servletPaths; // PKI configuration private Map<String, CAConfiguration> rootCas; public static TestPKI get() { return testPKI; } public static TestPKI load(String testPkiPath) throws Exception { testPKI = new TestPKI(); // load CA config HttpClient httpClient = new HttpClient(); GetMethod getMethod = new GetMethod(testPkiPath + "/" + ConfigurationServlet.PATH + "?" + ConfigurationServlet.ACTION + "=" + ConfigurationServlet.Action.GET); httpClient.executeMethod(getMethod); InputStream inputStream = getMethod.getResponseBodyAsStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String caString; while (null != (caString = br.readLine())) { String[] fields = caString.split(ConfigurationServlet.FIELD_SEPERATOR); testPKI.addSaveCa(fields[0], fields[1], Long.parseLong(fields[2]), Integer.parseInt(fields[3])); } // now get private keys and certificates for (CAConfiguration rootCa : testPKI.getRoots().values()) { loadParentCa(httpClient, testPkiPath, rootCa); } return testPKI; } public TestPKI() { this.rootCas = new HashMap<String, CAConfiguration>(); } /** * Start embedded jetty for this test PKI * * @throws Exception * something went wrong :o */ public void start(String host) throws Exception { LOG.debug("host=" + host); this.host = host; this.server = new Server(); Connector connector = new LocalConnector(); this.server.addConnector(connector); this.servletPaths = new LinkedList<String>(); /* * Add servlets */ addServlet(ConfigurationServlet.class, "/" + ConfigurationServlet.PATH); addServlet(CrlServlet.class, "/" + CrlServlet.PATH); addServlet(OcspServlet.class, "/" + OcspServlet.PATH); addServlet(CertificateServlet.class, "/" + CertificateServlet.PATH); addServlet(PrivateKeyServlet.class, "/" + PrivateKeyServlet.PATH); server.start(); createSocketConnector(); // save static for access in servlets testPKI = this; LOG.debug("Test CA started..."); } /** * Stop embedded jetty for this test PKI * * @throws Exception * something went wrong :o */ public void stop() throws Exception { this.server.stop(); LOG.debug("Test CA stopped..."); } private void addServlet(Class<? extends HttpServlet> servletClass, String contextPath) { Context context = new Context(null, new SessionHandler(), new SecurityHandler(), null, null); context.setContextPath(contextPath); // http://jira.codehaus.org/browse/JETTY-390 context.setAllowNullPathInfo(true); this.server.addHandler(context); ServletHandler handler = context.getServletHandler(); ServletHolder servletHolder = new ServletHolder(); servletHolder.setClassName(servletClass.getName()); servletHolder.setName(servletClass.getName()); handler.addServlet(servletHolder); ServletMapping servletMapping = new ServletMapping(); servletMapping.setServletName(servletClass.getName()); servletMapping.setPathSpecs(new String[] { "/*", contextPath }); handler.addServletMapping(servletMapping); servletPaths.add(contextPath); } private void createSocketConnector() throws Exception { SocketConnector connector = new SocketConnector(); connector.setHost(host); this.server.addConnector(connector); if (this.server.isStarted()) { connector.start(); } else { connector.open(); } path = "http://" + host + ":" + connector.getLocalPort(); } public String getPath() { return path; } public List<String> getServletPaths() { return this.servletPaths; } public Map<String, CAConfiguration> getRoots() { return this.rootCas; } public List<CAConfiguration> getLeaves() { List<CAConfiguration> leaves = new LinkedList<CAConfiguration>(); for (CAConfiguration rootCa : this.rootCas.values()) { leaves.addAll(getLeaves(rootCa)); } return leaves; } private List<CAConfiguration> getLeaves(CAConfiguration parent) { List<CAConfiguration> leaves = new LinkedList<CAConfiguration>(); if (parent.getChilds().isEmpty()) { leaves.add(parent); } else { for (CAConfiguration child : parent.getChilds()) { leaves.addAll(getLeaves(child)); } } return leaves; } /** * Add/Save CA configuration. * * @param name * CA name * @param root * optional root CA * @param crlRecords * # of CRL records to generate * @param crlRefresh * CRL refresh in minutes * @throws Exception * root CA not found, CA already existing, ... */ public void addSaveCa(String name, String root, long crlRecords, int crlRefresh) throws Exception { // LOG.debug("Add/Save CA: " + name + " root=" + root // + " crlRecords=" + crlRecords + " crlRefresh=" + crlRefresh); // find root if needed CAConfiguration rootCa = null; if (null != root && !root.isEmpty()) { rootCa = findCa(root); if (null == rootCa) { throw new Exception("Root CA " + root + " not found"); } } // add/save new config CAConfiguration ca = findCa(name); if (null == ca) { ca = new CAConfiguration(name, crlRecords, crlRefresh); } else { ca.setCrlRecords(crlRecords); ca.setCrlRefresh(crlRefresh); } // set root/childs ca.setRoot(rootCa); if (null != rootCa) { if (!rootCa.getChilds().contains(ca)) { rootCa.getChilds().add(ca); } } else { rootCas.put(name, ca); } } /** * Remove specified CA configuration * * @param caName * the Ca's name */ public void removeCa(String caName) { LOG.debug("remove CA configuration: " + caName); // check roots if (null != rootCas.get(caName)) { rootCas.remove(caName); return; } // nope, check deeper for (CAConfiguration root : rootCas.values()) { removeCa(caName, root); } } private void removeCa(String caName, CAConfiguration parent) { Iterator<CAConfiguration> iter = parent.getChilds().iterator(); while (iter.hasNext()) { CAConfiguration child = iter.next(); if (child.getName().equals(caName)) { // remove from root iter.remove(); // remove all childs below for (CAConfiguration childChild : child.getChilds()) { removeCa(childChild.getName()); } } else { removeCa(caName, child); } } } /** * Find specified CA configuration. * * @param caName * the CA's name * @return <code>null</code> if not found */ public CAConfiguration findCa(String caName) { // check roots CAConfiguration caConfig = rootCas.get(caName); if (null != caConfig) { return caConfig; } // nope, check deeper for (CAConfiguration root : rootCas.values()) { caConfig = findCa(caName, root); if (null != caConfig) { return caConfig; } } return null; } private CAConfiguration findCa(String caName, CAConfiguration parent) { for (CAConfiguration child : parent.getChilds()) { if (child.getName().equals(caName)) { return child; } else { CAConfiguration config = findCa(caName, child); if (null != config) { return config; } } } return null; } /** * Generate the PKI tree from the configuration * * @throws Exception * something went wrong. */ public void generate() throws Exception { LOG.debug("generate"); for (CAConfiguration caConfig : rootCas.values()) { caConfig.generate(); } LOG.debug("generation finished"); } private static void loadParentCa(HttpClient httpClient, String testPkiPath, CAConfiguration parentCa) throws Exception { loadCa(httpClient, testPkiPath, parentCa); for (CAConfiguration child : parentCa.getChilds()) { loadParentCa(httpClient, testPkiPath, child); } } private static void loadCa(HttpClient httpClient, String testPkiPath, CAConfiguration ca) throws Exception { LOG.debug("load CA: " + ca.getName()); CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); // load certificate URI certificateURI = new URI(testPkiPath + "/" + CertificateServlet.PATH + "?" + CertificateServlet.CA_QUERY_PARAM + "=" + ca.getName(), false); LOG.debug("URI: " + certificateURI.toString()); GetMethod getMethod = new GetMethod(certificateURI.toString()); httpClient.executeMethod(getMethod); X509Certificate certificate = (X509Certificate) certificateFactory .generateCertificate(getMethod.getResponseBodyAsStream()); ca.setCertificate(certificate); // load private key URI keyURI = new URI(testPkiPath + "/" + PrivateKeyServlet.PATH + "?" + PrivateKeyServlet.CA_QUERY_PARAM + "=" + ca.getName(), false); getMethod = new GetMethod(keyURI.toString()); httpClient.executeMethod(getMethod); PEMReader pemReader = new PEMReader(new InputStreamReader(getMethod.getResponseBodyAsStream())); KeyPair keyPair = (KeyPair) pemReader.readObject(); ca.setKeyPair(keyPair); } }