Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.cesnet.pki; import com.cesnet.pki.ejbca.Connector; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import java.net.UnknownServiceException; import java.nio.charset.Charset; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.text.ParseException; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.NamingException; import javax.xml.bind.DatatypeConverter; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.util.Store; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; /** * * @author jana */ public class DigicertConnector extends Connector { private final String digicertSection = "digicert"; private final String urlBase = "https://www.digicert.com/services/v2/"; private final int LIMIT = 1000; private final String key = properties.get(digicertSection, "apiKey"); private HashMap<Integer, String> parentId_has_apiKey; private HashMap<Integer, Integer> parentId_has_numOfCerts = new HashMap<>(); private HashMap<Integer, CertificateData> cache = new HashMap<>(); @Override public void generateValidCerts() { super.generateValidCerts(); // choose json language int lang = ORG_NAME; try { // get api keys to all organizations LdapConnector lc = new LdapConnector(); parentId_has_apiKey = lc.findApiKeysForDigicert(); // init cache = loadGeneratedData(); validCertificates = new TreeMap<>(); // count valid certificates int offset = 0; countValidCerts(offset); // save cache saveGeneratedData(cache); for (Map.Entry<Integer, Integer> entry : parentId_has_numOfCerts.entrySet()) { int parentId = entry.getKey(); String organizationName = lc.getOrganizationNameFromLdap(String.valueOf(parentId), lang); validCertificates.put(organizationName, entry.getValue()); } } catch (IOException | NamingException | JSONException | IllegalArgumentException | CMSException | ParseException | CertificateException ex) { Logger.getLogger(DigicertConnector.class.getName()).log(Level.SEVERE, null, ex); } } /** * Calls digicert by specific url with given offset * * @param urlSuffix remaining String to parse as a URL (url starts with https://www.digicert.com/services/v2/) * @param offset positive integer identifying the number of records to skip. If negative or equal zero offset is ignored. * @return JSONObject of requested data * @throws MalformedURLException if no protocol is specified, or an unknown protocol is found, or spec is null * @throws IOException if an I/O error occurs while creating the input stream * @throws JSONException if there is a syntax error in the source string or a duplicated key */ private JSONObject callDigicert(String urlSuffix, int offset) throws MalformedURLException, IOException, JSONException { String urlAdress = urlBase + urlSuffix; if (offset > 0) { urlAdress += "?offset=" + offset; } URL url = new URL(urlAdress); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("X-DC-DEVKEY", key); conn.setRequestProperty("Accept", "application/json"); conn.setDoOutput(true); String rawJson; try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) { rawJson = reader.readLine(); return new JSONObject(rawJson); } catch (Exception e) { System.out.println(e.getMessage()); try { Thread.sleep(1000 * 60 * 5); } catch (InterruptedException ex) { } return callDigicert(urlSuffix, offset); } } /** * Calls digicert by specific url with given api key * * @param urlSuffix the String to parse as a URL * @param apiKey api key * @return String of certificate base64 encoded data * @throws MalformedURLException if no protocol is specified, or an unknown protocol is found, or spec is null * @throws ProtocolException if the method cannot be reset or if the requested method isn't valid for HTTP * @throes SecurityException if a security manager is set and the method is "TRACE", but the "allowHttpTrace" NetPermission is not granted * @throws IllegalArgumentException if Input-buffer size is less or equal zero * @throws UnsupportedEncodingException if the named charset is not supported * @throws IOException if an I/O error occurs while creating the input stream * @throws UnknownServiceException if the protocol does not support input */ private String callDigicert(String urlSuffix, String apiKey) throws MalformedURLException, ProtocolException, SecurityException, IllegalArgumentException, UnsupportedEncodingException, IOException, UnknownServiceException { StringBuilder builder = new StringBuilder(); String currentLine; URL url = new URL(urlBase + urlSuffix); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setRequestProperty("X-DC-DEVKEY", apiKey); conn.setRequestProperty("Accept", "*/*"); conn.setDoOutput(true); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) { while ((currentLine = reader.readLine()) != null) { builder.append(currentLine); } } catch (Exception e) { System.out.println("apiKey\t" + apiKey); System.out.println(e.getMessage()); return null; } builder.delete(0, "-----BEGIN PKCS7-----".length()); // we do not want first line (-----BEGIN PKCS7-----) builder.delete(builder.length() - ("-----END PKCS7-----".length()), builder.length()); // neather -----END PKCS7----- return builder.toString(); } /** * @param offset positive integer identifying the number of records to skip * @throws JSONException if the key is not found or if the value is not a JSONArray. * @throws IOException if an I/O error occurs while creating the input stream * @throws CMSException * @throws ParseException if the beginning of the specified string cannot be parsed * @throws MalformedURLException if no protocol is specified, or an unknown protocol is found, or spec is null * @throws ProtocolException if the method cannot be reset or if the requested method isn't valid for HTTP * @throws IllegalArgumentException if Input-buffer size is less or equal zero * @throws UnsupportedEncodingException if the named charset is not supported * @throws UnknownServiceException if the protocol does not support input * @throws CertificateException this exception indicates one of a variety of certificate problems */ private void countValidCerts(int offset) throws JSONException, IOException, CMSException, ParseException, MalformedURLException, ProtocolException, IllegalArgumentException, UnsupportedEncodingException, UnknownServiceException, CertificateException { JSONObject orders = callDigicert("order/certificate", offset); JSONArray jsonArray = orders.getJSONArray("orders"); JSONObject pageInfo = (JSONObject) orders.get("page"); System.out.println(pageInfo); for (int i = 0; i < jsonArray.length(); i++) { JSONObject order = (JSONObject) jsonArray.get(i); String status = order.getString("status"); if (status.equals("issued") || status.equals("revoked")) { // if the result is in the cache if (cache.containsKey(order.getInt("id"))) { JSONObject container = order.getJSONObject("container"); int parentId = container.getInt("id"); // get certificate validation CertificateData data = cache.get(order.getInt("id")); if (isCertValidAtDay(data.certificate, referenceDate)) { int value = 0; if (parentId_has_numOfCerts.get(parentId) != null) { value = parentId_has_numOfCerts.get(parentId); } parentId_has_numOfCerts.put(parentId, value + 1); } // compute result } else { JSONObject certificate = order.getJSONObject("certificate"); int certificateId = certificate.getInt("id"); JSONObject container = order.getJSONObject("container"); int parentId = container.getInt("id"); if (parentId_has_apiKey.containsKey(parentId)) { // because of CESNET NREN decodeCertificate(order.getInt("id"), certificateId, parentId, container.getString("name"), parentId_has_apiKey.get(parentId)); } } } } int countResults = pageInfo.getInt("total"); offset += LIMIT; if (countResults > offset) { countValidCerts(offset); } } /** * downloads and decodes given certificate, updates HashMap of results * * @param certificateId certificate id * @param parentId id of parent organization * @param apiKey api key to access downloading certificate * @throws MalformedURLException if no protocol is specified, or an unknown protocol is found, or spec is null * @throws ProtocolException if the method cannot be reset or if the requested method isn't valid for HTTP * @throws IllegalArgumentException if Input-buffer size is less or equal zero * @throws UnsupportedEncodingException if the named charset is not supported * @throws IOException if an I/O error occurs while creating the input stream * @throws UnknownServiceException if the protocol does not support input * @throws ParseException if the beginning of the specified string cannot be parsed * @throws CMSException master exception type for all exceptions caused in OpenCms * @throws CertificateException this exception indicates one of a variety of certificate problems */ private void decodeCertificate(int orderId, int certificateId, int parentId, String parentName, String apiKey) throws MalformedURLException, ProtocolException, IllegalArgumentException, UnsupportedEncodingException, IOException, UnknownServiceException, CMSException, ParseException, CertificateException, JSONException { String certificate = callDigicert("certificate/" + certificateId + "/download/format/p7b", apiKey); if (certificate == null) { System.out.println("certificate is null"); System.out.println("orderId:\t" + orderId + "\tcertificateId:\t" + certificateId + "\tparentId:\t" + parentId + "\tparentName:\t" + parentName + "\tApiKey:\t" + apiKey); } else { byte[] source = DatatypeConverter .parseBase64Binary(new String(certificate.getBytes(Charset.forName("UTF-8")))); CMSSignedData signature = new CMSSignedData(source); Store cs = signature.getCertificates(); ArrayList<X509CertificateHolder> listCertData = new ArrayList(cs.getMatches(null)); // we want only first certificate X509Certificate cert = new JcaX509CertificateConverter().getCertificate(listCertData.get(0)); CertificateData data = new CertificateData(cert, orderId, parentId, parentName); // store found certificate in HashMap cache.put(orderId, data); if (isCertValidAtDay(cert, referenceDate)) { int value = 0; if (parentId_has_numOfCerts.get(parentId) != null) { value = parentId_has_numOfCerts.get(parentId); } parentId_has_numOfCerts.put(parentId, value + 1); } } } /** * saves once generated data of organization ids and validation dates * * @param data to by saved * @throws IOException if an I/O error occurs while writing stream header */ private void saveGeneratedData(HashMap<Integer, CertificateData> data) throws IOException { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data.properties"))) { oos.writeObject(data); } } /** * load generated data of organization ids and validation dates * * @return generated data if exists. Else returns new empty HashMap */ private HashMap<Integer, CertificateData> loadGeneratedData() { HashMap<Integer, CertificateData> data = new HashMap<>(); try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("data.properties"))) { Object readMap = ois.readObject(); if (readMap != null && readMap instanceof HashMap) { data.putAll((Map<? extends Integer, ? extends CertificateData>) readMap); } System.out.println(ANSI_GREEN + "Great :) Data already exist. The size is " + data.size()); } catch (IOException | ClassNotFoundException e) { // data do not exist yet System.out.println(ANSI_RED + "Data do not exist yet..."); } return data; } }