/* * Copyright (c) 2011 ICM Uniwersytet Warszawski All rights reserved. * See LICENCE file for licensing information. */ package eu.emi.security.authn.x509.helpers.ns; import java.io.FileNotFoundException; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.security.auth.x500.X500Principal; import eu.emi.security.authn.x509.StoreUpdateListener.Severity; import eu.emi.security.authn.x509.helpers.CachedElement; import eu.emi.security.authn.x509.helpers.ObserversHandler; import eu.emi.security.authn.x509.helpers.trust.OpensslTruststoreHelper; /** * Policy store common code. * <p> * This class it thread safe. * * @author K. Benedyczak */ public abstract class AbstractNamespacesStore implements NamespacesStore { private static final List<NamespacePolicy> EMPTY = Collections.emptyList(); protected final ObserversHandler observers; protected boolean openssl1Mode; public AbstractNamespacesStore(ObserversHandler observers, boolean openssl1Mode) { this.openssl1Mode = openssl1Mode; this.observers = observers; } protected abstract String getNotificationType(); protected abstract NamespacesParser getParser(String path); protected abstract String getFileSuffix(); protected List<NamespacePolicy> tryLoadNsPath(String path) { if (path == null) return EMPTY; NamespacesParser parser = getParser(path); try { List<NamespacePolicy> ret = parser.parse(); observers.notifyObservers(path, getNotificationType(), Severity.NOTIFICATION, null); return ret; } catch (FileNotFoundException e) { //OK - ignored. } catch (IOException e) { observers.notifyObservers(path, getNotificationType(), Severity.ERROR, e); } return EMPTY; } protected void tryLoadNsLocation(String location, List<NamespacePolicy> policies) { String path = OpensslTruststoreHelper.getNsFile(location, getFileSuffix()); policies.addAll(tryLoadNsPath(path)); } /** * Adds a given policy to a given map. It is assumed that the map is indexed by issuer hash * and the value maps are indexed by issuer id. * This method is useful only for stores which keep all their namespaces in memory. * @param policy policy to add * @param policies policy map to add to */ protected void addPolicy(NamespacePolicy policy, Map<String, Map<String, List<NamespacePolicy>>> policies) { String definedFor = policy.getDefinedFor(); Map<String, List<NamespacePolicy>> current = policies.get(definedFor); if (current == null) { current = new HashMap<String, List<NamespacePolicy>>(); policies.put(definedFor, current); } addPolicyToMap(policy, current); } /** * Adds policy to a map indexed by a policy issuer. * @param policy policy to add * @param map policy map to add to */ protected void addPolicyToMap(NamespacePolicy policy, Map<String, List<NamespacePolicy>> map) { String issuer = policy.getIssuer(); List<NamespacePolicy> currentList = map.get(issuer); if (currentList == null) { currentList = new ArrayList<NamespacePolicy>(); map.put(issuer, currentList); } currentList.add(policy); } @Override public List<NamespacePolicy> getPolicies(X509Certificate[] chain, int position) { X500Principal[] issuers = new X500Principal[chain.length]; for (int i=position; i<chain.length; i++) issuers[i] = chain[i].getIssuerX500Principal(); return getPolicies(issuers, position); } /** * Utility method useful for lazy stores. Retrieves a cached policies for the given ca hash and issuer. * If there is no policy in the cache then it is tried to load one from disk. The * loaded policy is cached before being returned. * @param policies policies * @param definedForHash defined for hash * @param issuer issuer * @param path path * @param maxTTL max TTL * @return cached policies */ protected List<NamespacePolicy> getCachedPolicies(Map<String, CachedElement<Map<String, List<NamespacePolicy>>>> policies, String definedForHash, String issuer, String path, long maxTTL) { CachedElement<Map<String, List<NamespacePolicy>>> cachedEntry = policies.get(definedForHash); if (cachedEntry != null && !cachedEntry.isExpired(maxTTL)) { Map<String, List<NamespacePolicy>> policiesMap = cachedEntry.getElement(); return policiesMap.get(issuer); } List<NamespacePolicy> loaded = tryLoadNsPath(path); if (loaded != null) { Map<String, List<NamespacePolicy>> current = new HashMap<String, List<NamespacePolicy>>(); for (NamespacePolicy policy: loaded) addPolicyToMap(policy, current); policies.put(definedForHash, new CachedElement<Map<String,List<NamespacePolicy>>>(current)); } return loaded; } }