package org.cagrid.trust.service.core; import java.io.File; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.cxf.configuration.security.KeyManagersType; import org.apache.cxf.configuration.security.KeyStoreType; import org.cagrid.core.soapclient.ClientConfigurer; import org.cagrid.core.xml.XMLUtils; import org.cagrid.gaards.pki.CertUtil; import org.cagrid.gts.model.Status; import org.cagrid.gts.soapclient.GTSSoapClientFactory; import org.cagrid.gts.ws.client.GTSClient; import org.cagrid.gts.wsrf.stubs.FindTrustedAuthoritiesRequest; import org.cagrid.gts.wsrf.stubs.FindTrustedAuthoritiesRequest.Filter; import org.cagrid.gts.wsrf.stubs.FindTrustedAuthoritiesResponse; import org.cagrid.gts.wsrf.stubs.GTSPortType; import org.cagrid.trust.model.AddedTrustedCAs; import org.cagrid.trust.model.ExcludedCAs; import org.cagrid.trust.model.Message; import org.cagrid.trust.model.MessageType; import org.cagrid.trust.model.Messages; import org.cagrid.trust.model.RemovedTrustedCAs; import org.cagrid.trust.model.SyncDescription; import org.cagrid.trust.model.SyncDescriptor; import org.cagrid.trust.model.SyncReport; import org.cagrid.trust.model.TrustLevels; import org.cagrid.trust.model.TrustedAuthority; import org.cagrid.trust.model.TrustedAuthorityFilter; import org.cagrid.trust.model.TrustedCA; import org.globus.common.CoGProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author <A href="mailto:langella@bmi.osu.edu">Stephen Langella </A> * @author <A href="mailto:oster@bmi.osu.edu">Scott Oster </A> * @author <A href="mailto:hastings@bmi.osu.edu">Shannon Hastings </A> * @version $Id: ArgumentManagerTable.java,v 1.2 2004/10/15 16:35:16 langella * Exp $ */ public class SyncGTS implements Synchronizer { private final static String CERTIFICATE_EXTENSION = "cert"; private final static String CRL_EXTENSION = "crl"; private final static String METADATA_EXTENSION = "xml"; private Map<String, TrustedCAFileListing> caListings; private Logger log; private List<Message> messages; private HistoryManager historyManager; private File trustedCertificatesDirectory; private ClientConfigurer clientConfigurer; private Map<String, GTSClient> clients; public SyncGTS() { this.trustedCertificatesDirectory = new File("."); log = LoggerFactory.getLogger(this.getClass().getName()); this.clients = new HashMap<String, GTSClient>(); } private GTSClient getClient(String url){ if(this.clients.containsKey(url)){ return this.clients.get(url); }else{ GTSClient client = new GTSClient(url); getClientConfigurer().configureClient(client); this.clients.put(url,client); return client; } } public HistoryManager getHistoryManager() { return historyManager; } public void setTrustedCertificatesDirectory(String dir) { this.trustedCertificatesDirectory = new File(dir); } public void setHistoryManager(HistoryManager historyManager) { this.historyManager = historyManager; } private void reset() { this.caListings = null; messages = new ArrayList<Message>(); } public SyncReport sync(SyncDescription description) { SyncReport report = new SyncReport(); try { reset(); Set<String> unableToSync = new HashSet<String>(); report.setSyncDescription(description); Date now = new Date(); report.setTimeOfSync(now); Map<String, TrustedCAListing> master = new HashMap<String, TrustedCAListing>(); String error = null; List<SyncDescriptor> list = description.getSyncDescriptors(); for (SyncDescriptor des : list) { String uri = des.getGTS(); this.log.info("Syncing with the GTS " + uri); Set<org.cagrid.gts.model.TrustedAuthority> taSet = new HashSet<org.cagrid.gts.model.TrustedAuthority>(); List<TrustedAuthorityFilter> filters = des.getTrustedAuthorityFilters(); int filterCount = 0; for (TrustedAuthorityFilter f : filters) { filterCount = filterCount + 1; try { GTSClient client = getClient(uri); List<org.cagrid.gts.model.TrustedAuthority> tas = client.findTrustedAuthorities(convert(f)); int length = 0; this.log.debug("Successfully synced with " + uri + " using filter " + filterCount + " the search found " + length + " Trusted Authority(s)!!!"); for (org.cagrid.gts.model.TrustedAuthority ta : tas) { taSet.add(ta); } } catch (Exception e) { unableToSync.add(uri); Message mess = new Message(); mess.setType(MessageType.ERROR); mess.setValue("An error occurred syncing with " + uri + " using filter " + filterCount + "\n " + e.getMessage()); messages.add(mess); log.error(mess.getValue(), e); } } // Write all to the master list; Iterator<org.cagrid.gts.model.TrustedAuthority> itr = taSet.iterator(); while (itr.hasNext()) { org.cagrid.gts.model.TrustedAuthority ta = itr.next(); if (master.containsValue(ta.getName())) { TrustedCAListing gta = (TrustedCAListing) master.get(ta.getName()); String msg = "Conflict Detected: The Trusted Authority " + ta.getName() + " was determined to be trusted by both " + gta.getService() + " and " + uri + "."; Message mess = new Message(); mess.setType(MessageType.WARNING); mess.setValue(msg); messages.add(mess); } else { master.put(ta.getName(), new TrustedCAListing(uri, convert(ta), des)); } } this.log.debug("Done syncing with the GTS " + uri + " " + taSet.size() + " Trusted Authority(s) found!!!"); if (error != null) { break; } } // Create a list of exclude certificate authorities and remove // all excluded certificates from the master list. Set<String> excluded = new HashSet<String>(); ExcludedCAs ex = description.getExcludedCAs(); if (ex != null) { List<String> caSubjects = ex.getCASubjects(); if (caSubjects != null) { for (String subject : caSubjects) { excluded.add(subject); if (master.containsKey(subject)) { master.remove(subject); Message m = new Message(); m.setType(MessageType.WARNING); m.setValue("Ignoring the CA " + subject + " that was obtained in the sync because it is the excludes list!!!"); log.warn(m.getValue()); this.messages.add(m); } } } } // Write the master list out and generate signing policy this.readInCurrentCADirectory(description); Set<String> completeCASetByName = new HashSet<String>(); Set<String> completeCASetByHash = new HashSet<String>(); // Remove all CAs from the ca directory and COMPLETE list that // except the following: // Any CA in the exclude list. // Any CA in the unable to sync list that is not in the master // list. int removeCount = 0; List<TrustedCA> removedList = new ArrayList<TrustedCA>(); Iterator<TrustedCAFileListing> del = caListings.values().iterator(); while (del.hasNext()) { TrustedCAFileListing fl = (TrustedCAFileListing) del.next(); TrustedCA ca = new TrustedCA(); X509Certificate cert = null; if (fl.getCertificate() != null) { try { cert = CertUtil.loadCertificate(fl.getCertificate()); ca.setName(cert.getSubjectDN().getName()); ca.setCertificateFile(fl.getCertificate().getAbsolutePath()); if (excluded.contains(ca.getName())) { Message m = new Message(); m.setType(MessageType.INFO); m.setValue("The CA " + ca.getName() + " was not removed because it is the exclude list."); this.messages.add(m); log.info(m.getValue()); completeCASetByName.add(cert.getSubjectDN().getName()); completeCASetByHash.add(fl.getName()); continue; } } catch (Exception exception) { ca.setCertificateFile(fl.getCertificate().getAbsolutePath()); Message err = new Message(); err.setType(MessageType.ERROR); err.setValue("Error loading the certificate, " + fl.getCertificate().getAbsolutePath() + ": \n" + exception.getMessage()); this.messages.add(err); log.error(err.getValue()); } } if (fl.getMetadata() != null) { try { TrustedCA tca = (TrustedCA) XMLUtils.fromXMLFile(TrustedCA.class, fl.getMetadata()); ca.setDiscoveredOn(tca.getDiscoveredOn()); ca.setExpiresOn(tca.getExpiresOn()); if ((unableToSync.contains(tca.getGTS())) && (!master.containsKey(tca.getName()))) { if (now.before(tca.getExpiresOn())) { Message m = new Message(); m.setType(MessageType.WARNING); m.setValue("Unable to communicate with the GTS " + tca.getGTS() + " did not remove the the CA " + tca.getName() + " because it was not expired."); this.messages.add(m); log.warn(m.getValue()); completeCASetByName.add(cert.getSubjectDN().getName()); completeCASetByHash.add(fl.getName()); continue; } } } catch (Exception e) { log.error(e.getMessage(), e); } } removeCount = removeCount + 1; if (fl.getCertificate() != null) { if (fl.getCertificate().delete()) { log.debug("Removed the certificate (" + fl.getCertificate().getAbsolutePath() + ") for the CA " + ca.getName() + "."); } else { Message err = new Message(); err.setType(MessageType.ERROR); err.setValue("Error removing the certificate (" + fl.getCertificate().getAbsolutePath() + ") for the CA " + ca.getName() + "."); this.messages.add(err); log.error(err.getValue()); } } if (fl.getCRL() != null) { ca.setCRLFile(fl.getCRL().getAbsolutePath()); if (fl.getCRL().delete()) { log.debug("Removed the CRL (" + fl.getCRL().getAbsolutePath() + ") for the CA " + ca.getName() + "."); } else { Message err = new Message(); err.setType(MessageType.ERROR); err.setValue("Error removing the CRL (" + fl.getCRL().getAbsolutePath() + ") for the CA " + ca.getName() + "."); this.messages.add(err); log.error(err.getValue()); } } if (fl.getMetadata() != null) { ca.setMetadataFile(fl.getMetadata().getAbsolutePath()); if (fl.getMetadata().delete()) { log.debug("Removed the CA Metadata (" + fl.getMetadata().getAbsolutePath() + ") for the CA " + ca.getName() + "."); } else { Message err = new Message(); err.setType(MessageType.ERROR); err.setValue("Error removing the metadata (" + fl.getMetadata().getAbsolutePath() + ") for the CA " + ca.getName() + "."); this.messages.add(err); log.error(err.getValue()); } } removedList.add(ca); } RemovedTrustedCAs rtc = new RemovedTrustedCAs(); rtc.getTrustedCAs().addAll(removedList); report.setRemovedTrustedCAs(rtc); Message mess2 = new Message(); mess2.setType(MessageType.INFO); mess2.setValue("Successfully removed " + removeCount + " Trusted Authority(s) from " + CoGProperties.getDefault().getCaCertLocations()); messages.add(mess2); log.info(mess2.getValue()); int taCount = 0; Iterator<TrustedCAListing> itr = master.values().iterator(); List<TrustedCA> addedList = new ArrayList<TrustedCA>(); while (itr.hasNext()) { taCount = taCount + 1; File caFile = null; File crlFile = null; File metadataFile = null; String caHash = null; String subject = null; try { TrustedCAListing listing = (TrustedCAListing) itr.next(); TrustedAuthority ta = listing.getTrustedAuthority(); X509Certificate cert = CertUtil.loadCertificate(ta.getCertificate().getCertificateEncodedString()); caHash = CertUtil.getHashCode(cert); TrustedCA ca = new TrustedCA(); subject = cert.getSubjectDN().getName(); ca.setName(subject); ca.setGTS(listing.getService()); if ((completeCASetByName.contains(cert.getSubjectDN())) && (excluded.contains(cert.getSubjectDN()))) { Message m = new Message(); m.setType(MessageType.WARNING); m.setValue("Ignoring the CA " + ca.getName() + " obtained from the GTS " + ca.getGTS() + " because the CA is in the excludes list."); this.messages.add(m); log.warn(m.getValue()); } else if ((completeCASetByName.contains(cert.getSubjectDN())) && (!excluded.contains(cert.getSubjectDN()))) { Message m = new Message(); m.setType(MessageType.WARNING); m.setValue("Ignoring the CA " + ca.getName() + " obtained from the GTS " + ca.getGTS() + " because the CA is already trusted."); this.messages.add(m); log.warn(m.getValue()); } else if (completeCASetByHash.contains(caHash)) { Message m = new Message(); m.setType(MessageType.WARNING); m.setValue("Ignoring the CA " + ca.getName() + " obtained from the GTS " + ca.getGTS() + " because a CA with the hash " + caHash + " already exists."); this.messages.add(m); log.warn(m.getValue()); } else { String filePrefix = this.trustedCertificatesDirectory.getAbsolutePath() + File.separator + caHash; caFile = new File(filePrefix + "." + CERTIFICATE_EXTENSION); crlFile = new File(filePrefix + "." + CRL_EXTENSION); metadataFile = new File(filePrefix + "." + METADATA_EXTENSION); ca.setMetadataFile(metadataFile.getAbsolutePath()); CertUtil.writeCertificate(cert, caFile); ca.setCertificateFile(caFile.getAbsolutePath()); log.debug("Wrote out the certificate for the Trusted Authority " + ta.getName() + " to the file " + caFile.getAbsolutePath()); if (ta.getCRL() != null) { if (ta.getCRL().getCrlEncodedString() != null) { X509CRL crl = CertUtil.loadCRL(ta.getCRL().getCrlEncodedString()); CertUtil.writeCRL(crl, crlFile); ca.setCRLFile(crlFile.getAbsolutePath()); log.debug("Wrote out the CRL for the Trusted Authority " + ta.getName() + " to the file " + crlFile.getAbsolutePath()); } } Calendar cal = new GregorianCalendar(); ca.setDiscoveredOn(cal.getTime()); if (listing.getDescriptor().getExpiration() != null) { cal.add(Calendar.HOUR_OF_DAY, listing.getDescriptor().getExpiration().getHours()); cal.add(Calendar.MINUTE, listing.getDescriptor().getExpiration().getMinutes()); cal.add(Calendar.SECOND, listing.getDescriptor().getExpiration().getSeconds()); ca.setExpiresOn(cal.getTime()); } else { ca.setExpiresOn(cal.getTime()); } XMLUtils.toXMLFile(ca, metadataFile); log.debug("Wrote out the metadata for the Trusted Authority " + ta.getName() + " to the file " + metadataFile.getAbsolutePath()); completeCASetByName.add(subject); completeCASetByHash.add(caHash); addedList.add(ca); } } catch (Exception e) { log.error("An unexpected error occurred writing out the Trusted Authorities!!!", e); if (caFile != null) { caFile.delete(); } if (crlFile != null) { crlFile.delete(); } if (metadataFile != null) { metadataFile.delete(); } if (subject != null) { completeCASetByName.remove(subject); } if (caHash != null) { completeCASetByHash.remove(caHash); } } } Message mess = new Message(); mess.setType(MessageType.INFO); mess.setValue("Successfully wrote out " + taCount + " Trusted Authority(s) to " + this.trustedCertificatesDirectory.getAbsolutePath()); messages.add(mess); log.info(mess.getValue()); AddedTrustedCAs atc = new AddedTrustedCAs(); atc.getTrustedCAs().addAll(addedList); report.setAddedTrustedCAs(atc); } catch (Exception e) { log.error(e.getMessage(), e); Message error = new Message(); error.setType(MessageType.FATAL); error.setValue(e.getMessage()); messages.add(error); } Messages reportMessages = new Messages(); reportMessages.getMessages().addAll(messages); report.setMessages(reportMessages); // Log Report; if (getHistoryManager() != null) { try { getHistoryManager().addReport(report); if (description.getCacheSize() != null) { getHistoryManager().prune(description.getCacheSize()); } } catch (Exception e) { log.error(e.getMessage(), e); } } else { log.warn("A sync report was not logged, no history manager was configured."); } return report; } private void readInCurrentCADirectory(SyncDescription description) throws Exception { caListings = new HashMap<String, TrustedCAFileListing>(); log.info("Taking Snapshot of Trusted CA Directory (" + this.trustedCertificatesDirectory.getAbsolutePath() + ")...."); if (this.trustedCertificatesDirectory.exists()) { if (!this.trustedCertificatesDirectory.isDirectory()) { Message mess = new Message(); mess.setType(MessageType.FATAL); mess.setValue("The Trusted Certificates directory, " + this.trustedCertificatesDirectory.getAbsolutePath() + " is not a directory."); messages.add(mess); throw new Exception(mess.getValue()); } } else { boolean create = this.trustedCertificatesDirectory.mkdirs(); if (!create) { Message mess = new Message(); mess.setType(MessageType.FATAL); mess.setValue("The Trusted Certificates directory, " + this.trustedCertificatesDirectory.getAbsolutePath() + " does not exist and could not be created."); messages.add(mess); throw new Exception(mess.getValue()); } } File[] list = this.trustedCertificatesDirectory.listFiles(); for (int i = 0; i < list.length; i++) { String fn = list[i].getName(); int index = fn.lastIndexOf("."); if (index == -1) { handleUnexpectedFile(description, list[i]); continue; } String name = fn.substring(0, index); String extension = fn.substring(index + 1); TrustedCAFileListing ca = (TrustedCAFileListing) this.caListings.get(name); if (ca == null) { ca = new TrustedCAFileListing(name); caListings.put(name, ca); } if (extension.equals(CERTIFICATE_EXTENSION)) { ca.setCertificate(list[i]); } else if (extension.equals(CRL_EXTENSION)) { ca.setCRL(list[i]); } else if (extension.equals(METADATA_EXTENSION)) { ca.setMetadata(list[i]); } else { handleUnexpectedFile(description, list[i]); continue; } } log.debug("Found " + caListings.size() + " Trusted CAs found!!!"); Message mess = new Message(); mess.setType(MessageType.INFO); mess.setValue("A pre synchronization snapshot of the Trusted CA Directory found " + caListings.size() + " Trusted CAs."); messages.add(mess); log.info("DONE -Taking Snapshot of Trusted CA Directory, " + caListings.size() + " Trusted CAs found!!!"); } private void handleUnexpectedFile(SyncDescription description, File f) { if (description.isDeleteInvalidFiles()) { Message mess = new Message(); mess.setType(MessageType.WARNING); mess.setValue("The file " + f.getAbsolutePath() + " is unexpected and will be removed!!!"); messages.add(mess); log.warn(mess.getValue()); f.delete(); } else { Message mess = new Message(); mess.setType(MessageType.WARNING); mess.setValue("The file " + f.getAbsolutePath() + " is unexpected and will be ignored!!!"); messages.add(mess); log.warn(mess.getValue()); } } public static TrustedAuthority convert(org.cagrid.gts.model.TrustedAuthority ta) { TrustedAuthority authority = new TrustedAuthority(); authority.setAuthorityGTS(ta.getAuthorityGTS()); if (ta.getCertificate() != null) { org.cagrid.gts.model.X509Certificate c = ta.getCertificate(); org.cagrid.trust.model.X509Certificate cert = new org.cagrid.trust.model.X509Certificate(); cert.setCertificateEncodedString(c.getCertificateEncodedString()); authority.setCertificate(cert); } if (ta.getCRL() != null) { org.cagrid.gts.model.X509CRL c = ta.getCRL(); org.cagrid.trust.model.X509CRL crl = new org.cagrid.trust.model.X509CRL(); crl.setCrlEncodedString(c.getCrlEncodedString()); authority.setCRL(crl); } authority.setExpires(ta.getExpires()); authority.setIsAuthority(ta.isIsAuthority()); authority.setLastUpdated(ta.getLastUpdated()); authority.setName(ta.getName()); authority.setSourceGTS(ta.getSourceGTS()); if (ta.getStatus() != null) { authority.setStatus(org.cagrid.trust.model.Status.fromValue(ta.getStatus().value())); } if (ta.getTrustLevels() != null) { org.cagrid.gts.model.TrustLevels ls = ta.getTrustLevels(); TrustLevels levels = new TrustLevels(); List<String> list = ls.getTrustLevel(); for (String l : list) { levels.getTrustLevels().add(l); } authority.setTrustLevels(levels); } return authority; } public static org.cagrid.gts.model.TrustedAuthorityFilter convert(TrustedAuthorityFilter f) { org.cagrid.gts.model.TrustedAuthorityFilter filter = new org.cagrid.gts.model.TrustedAuthorityFilter(); filter.setAuthorityGTS(f.getAuthorityGTS()); filter.setCertificateDN(f.getCertificateDN()); filter.setName(f.getName()); filter.setSourceGTS(f.getSourceGTS()); if (f.getStatus() != null) { filter.setStatus(Status.fromValue(f.getStatus().value())); } if (f.getTrustLevels() != null) { TrustLevels ls = f.getTrustLevels(); org.cagrid.gts.model.TrustLevels levels = new org.cagrid.gts.model.TrustLevels(); List<String> list = ls.getTrustLevels(); for (String l : list) { levels.getTrustLevel().add(l); } filter.setTrustLevels(levels); } return filter; } public ClientConfigurer getClientConfigurer() { return clientConfigurer; } public void setClientConfigurer(ClientConfigurer clientConfigurer) { this.clientConfigurer = clientConfigurer; } }