/********************************************************************** * $Source: /cvsroot/jameica/jameica.webadmin/src/de/willuhn/jameica/webadmin/rest/Certificate.java,v $ * $Revision: 1.9 $ * $Date: 2011/06/21 10:03:29 $ * $Author: willuhn $ * $Locker: $ * $State: Exp $ * * Copyright (c) by willuhn software & services * All rights reserved * **********************************************************************/ package de.willuhn.jameica.webadmin.rest; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.lang.StringUtils; import org.json.JSONArray; import org.json.JSONObject; import de.willuhn.jameica.messaging.StatusBarMessage; import de.willuhn.jameica.security.Principal; import de.willuhn.jameica.system.Application; import de.willuhn.jameica.webadmin.annotation.Doc; import de.willuhn.jameica.webadmin.annotation.Path; import de.willuhn.jameica.webadmin.annotation.Request; import de.willuhn.jameica.webadmin.annotation.Response; import de.willuhn.jameica.webadmin.messaging.TrustMessageConsumer; import de.willuhn.logging.Logger; import de.willuhn.util.ApplicationException; import de.willuhn.util.I18N; /** * REST-Kommando fuer den Zugriff auf die Zertifikate. */ @Doc("System: Liefert Informationen �ber die in Jameica installierten SSL-Zertifikate") public class Certificate implements AutoRestBean { private final static I18N i18n = de.willuhn.jameica.system.Application.getPluginLoader().getPlugin(de.willuhn.jameica.webadmin.Plugin.class).getResources().getI18N(); @Request private HttpServletRequest request = null; @Response private HttpServletResponse response = null; /** * Liefert die Details des angegebenen Zertifikates. * Die Funktion erwartet als Parameter den SHA1-Hash des Zertifikates. * @param sha1 der SHA1-Fingerprint des Zertifikates. * @return die Details des angegebenen Zertifikates. * @throws IOException */ @Doc(value="Liefert die Details des angegebenen Zertifikates", example="certs/get/12:34:56:78:90") @Path("/certs/get/(.*)$") public JSONObject getDetails(String sha1) throws IOException { X509Certificate c = getCertificate(sha1); de.willuhn.jameica.security.Certificate cert = new de.willuhn.jameica.security.Certificate(c); try { Map all = new HashMap(); { Map map = new HashMap(); DateFormat DATEFORMAT = new SimpleDateFormat("dd.MM.yyyy"); map.put("from",DATEFORMAT.format(c.getNotBefore())); map.put("to", DATEFORMAT.format(c.getNotAfter())); all.put("valid",map); } { Map map = new HashMap(); Principal ps = cert.getSubject(); map.put(Principal.COMMON_NAME, StringUtils.trimToEmpty(ps.getAttribute(Principal.COMMON_NAME))); map.put(Principal.COUNTRY, StringUtils.trimToEmpty(ps.getAttribute(Principal.COUNTRY))); map.put(Principal.DISTINGUISHED_NAME, StringUtils.trimToEmpty(ps.getAttribute(Principal.DISTINGUISHED_NAME))); map.put(Principal.LOCALITY, StringUtils.trimToEmpty(ps.getAttribute(Principal.LOCALITY))); map.put(Principal.ORGANIZATION, StringUtils.trimToEmpty(ps.getAttribute(Principal.ORGANIZATION))); map.put(Principal.ORGANIZATIONAL_UNIT,StringUtils.trimToEmpty(ps.getAttribute(Principal.ORGANIZATIONAL_UNIT))); map.put(Principal.STATE, StringUtils.trimToEmpty(ps.getAttribute(Principal.STATE))); all.put("subject",map); } { Map map = new HashMap(); Principal pi = cert.getIssuer(); map.put(Principal.COMMON_NAME, StringUtils.trimToEmpty(pi.getAttribute(Principal.COMMON_NAME))); map.put(Principal.COUNTRY, StringUtils.trimToEmpty(pi.getAttribute(Principal.COUNTRY))); map.put(Principal.DISTINGUISHED_NAME, StringUtils.trimToEmpty(pi.getAttribute(Principal.DISTINGUISHED_NAME))); map.put(Principal.LOCALITY, StringUtils.trimToEmpty(pi.getAttribute(Principal.LOCALITY))); map.put(Principal.ORGANIZATION, StringUtils.trimToEmpty(pi.getAttribute(Principal.ORGANIZATION))); map.put(Principal.ORGANIZATIONAL_UNIT,StringUtils.trimToEmpty(pi.getAttribute(Principal.ORGANIZATIONAL_UNIT))); map.put(Principal.STATE, StringUtils.trimToEmpty(pi.getAttribute(Principal.STATE))); all.put("issuer",map); } { Map map = new HashMap(); map.put("serial", c.getSerialNumber().toString()); map.put("sha1", cert.getSHA1Fingerprint()); map.put("sha256", cert.getSHA256Fingerprint()); all.put("cert",map); } return new JSONObject(all); } catch (Exception e) { Logger.error("unable to load certificate " + sha1,e); throw new IOException("unable to load certificate " + sha1); } } /** * Liefert das Zertifikate mit dem genannten Fingerprint. * @param sha1 der Fingerprint. * @return das Zertifikate. * @throws IOException */ private X509Certificate getCertificate(String sha1) throws IOException { if (sha1 == null || sha1.length() == 0) throw new IOException("no sha1 hash given"); try { X509Certificate[] certs = Application.getSSLFactory().getTrustedCertificates(); for (X509Certificate c:certs) { de.willuhn.jameica.security.Certificate cert = new de.willuhn.jameica.security.Certificate(c); if (cert.getSHA1Fingerprint().equals(sha1)) return c; } throw new IOException("certificate " + sha1 + " not found"); } catch (ApplicationException ae) { throw new IOException(ae.getMessage()); } catch (Exception e) { Logger.error("unable to load certificate " + sha1,e); throw new IOException("unable to load certificate " + sha1); } } /** * Liefert die installierten Zertifikate. * @return die Liste der Zertifikate * @throws IOException */ @Doc(value="Liefert eine Liste der installierten SSL-Zertifikate", example="certs/list") @Path("/certs/list$") public JSONArray getList() throws IOException { try { List<JSONObject> list = new ArrayList(); X509Certificate[] certs = Application.getSSLFactory().getTrustedCertificates(); for (int i=0;i<certs.length;++i) { de.willuhn.jameica.security.Certificate cert = new de.willuhn.jameica.security.Certificate(certs[i]); list.add(getDetails(cert.getSHA1Fingerprint())); } return new JSONArray(list); } catch (ApplicationException ae) { throw new IOException(ae.getMessage()); } catch (Exception e) { Logger.error("unable to load certificates",e); throw new IOException("unable to load certificates: " + e.getMessage()); } } /** * Action zum Import eines SSL-Zertifikates. */ public void upload() { // Siehe PassportsRdh if (!ServletFileUpload.isMultipartContent(request)) return; TrustMessageConsumer mc = null; try { ServletFileUpload upload = new ServletFileUpload(); FileItemIterator iter = upload.getItemIterator(request); InputStream is = null; while (iter.hasNext()) { FileItemStream item = iter.next(); if (item.isFormField()) continue; String name = item.getFieldName(); if (name != null && name.equals("filename")) { is = item.openStream(); break; } } if (is == null) throw new ApplicationException(i18n.tr("Keine Zertifikatsdatei ausgew�hlt")); final X509Certificate c = Application.getSSLFactory().loadCertificate(is); if (c == null) throw new ApplicationException(i18n.tr("Zertifikat nicht lesbar")); mc = new TrustMessageConsumer(); Application.getMessagingFactory().registerMessageConsumer(mc); Application.getSSLFactory().addTrustedCertificate(c); Application.getMessagingFactory().sendMessage(new StatusBarMessage(i18n.tr("Zertifikat importiert"),StatusBarMessage.TYPE_SUCCESS)); response.sendRedirect("/webadmin/"); // Zurueck zur Startseite } catch (ApplicationException ae) { Application.getMessagingFactory().sendMessage(new StatusBarMessage(ae.getMessage(),StatusBarMessage.TYPE_ERROR)); } catch (Exception e) { Logger.error("error while uploading certificate",e); Application.getMessagingFactory().sendMessage(new StatusBarMessage(i18n.tr("Fehler beim Import des Zertifikates"),StatusBarMessage.TYPE_ERROR)); } finally { if (mc != null) Application.getMessagingFactory().unRegisterMessageConsumer(mc); } } /** * Action zum Herunterladen eines Zertifikates. * @throws IOException */ public void download() throws IOException { String sha1 = request.getParameter("sha1"); X509Certificate c = getCertificate(sha1); de.willuhn.jameica.security.Certificate cert = new de.willuhn.jameica.security.Certificate(c); try { byte[] data = c.getEncoded(); response.setContentLength(data.length); response.setContentType("application/octet-stream"); // application/x-x509-ca-cert // application/octet-stream response.setHeader("Content-Disposition","attachment; filename=\"" + cert.getSubject().getAttribute(Principal.COMMON_NAME) + ".crt\""); OutputStream os = response.getOutputStream(); os.write(data); os.flush(); Application.getMessagingFactory().sendMessage(new StatusBarMessage(i18n.tr("Zertifikat heruntergeladen"),StatusBarMessage.TYPE_SUCCESS)); } catch (IOException ioe) { throw ioe; } catch (Exception e) { Logger.error("unable to delete certificate " + sha1,e); throw new IOException("unable to delete certificate " + sha1); } } /** * Action zum Loeschen eines Zertifikates. * @throws IOException */ public void delete() throws IOException { String sha1 = request.getParameter("sha1"); X509Certificate c = getCertificate(sha1); try { Application.getSSLFactory().removeTrustedCertificate(c); Application.getMessagingFactory().sendMessage(new StatusBarMessage(i18n.tr("Zertifikat gel�scht"),StatusBarMessage.TYPE_SUCCESS)); response.sendRedirect("/webadmin/"); // Zurueck zur Startseite } catch (ApplicationException ae) { throw new IOException(ae.getMessage()); } catch (IOException ioe) { throw ioe; } catch (Exception e) { Logger.error("unable to delete certificate " + sha1,e); throw new IOException("unable to delete certificate " + sha1); } } } /********************************************************************** * $Log: Certificate.java,v $ * Revision 1.9 2011/06/21 10:03:29 willuhn * @B Beim Klick auf "Zertifikats-Details" wurde u.U. eine NPE angezeigt * @N Download von Zertifikaten * * Revision 1.8 2011-01-27 16:26:54 willuhn * @N Importieren und Loeschen von SSL-Zertifikaten * * Revision 1.7 2010-11-02 00:56:31 willuhn * @N Umstellung des Webfrontends auf Velocity/Webtools * * Revision 1.6 2010/05/12 10:59:20 willuhn * @N Automatische Dokumentations-Seite fuer die REST-Beans basierend auf der Annotation "Doc" * * Revision 1.5 2010/05/11 14:59:48 willuhn * @N Automatisches Deployment von REST-Beans * * Revision 1.4 2010/03/18 09:29:35 willuhn * @N Wenn REST-Beans Rueckgabe-Werte liefern, werrden sie automatisch als toString() in den Response-Writer geschrieben **********************************************************************/