/*
* 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;
}
}