/* * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.provider.certpath.ldap; import java.io.ByteArrayInputStream;import java.io.IOException;import java.math.BigInteger;import java.net.URI;import java.util.*;import javax.naming.Context;import javax.naming.NamingEnumeration;import javax.naming.NamingException;import javax.naming.NameNotFoundException;import javax.naming.directory.Attribute;import javax.naming.directory.Attributes;import javax.naming.directory.BasicAttributes;import javax.naming.directory.DirContext;import javax.naming.directory.InitialDirContext; import java.security.*;import java.security.cert.Certificate;import java.security.cert.*;import javax.security.auth.x500.X500Principal; import sun.misc.HexDumpEncoder;import sun.security.provider.certpath.X509CertificatePair;import sun.security.util.Cache;import sun.security.util.Debug;import sun.security.x509.X500Name;import sun.security.action.GetPropertyAction; /** * A <code>CertStore</code> that retrieves <code>Certificates</code> and * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema * (RFC 2587): * <a href="http://www.ietf.org/rfc/rfc2587.txt"> * http://www.ietf.org/rfc/rfc2587.txt</a>. * <p> * Before calling the {@link #engineGetCertificates engineGetCertificates} or * {@link #engineGetCRLs engineGetCRLs} methods, the * {@link #LDAPCertStore(CertStoreParameters) * LDAPCertStore(CertStoreParameters)} constructor is called to create the * <code>CertStore</code> and establish the DNS name and port of the LDAP * server from which <code>Certificate</code>s and <code>CRL</code>s will be * retrieved. * <p> * <b>Concurrent Access</b> * <p> * As described in the javadoc for <code>CertStoreSpi</code>, the * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods * must be thread-safe. That is, multiple threads may concurrently * invoke these methods on a single <code>LDAPCertStore</code> object * (or more than one) with no ill effects. This allows a * <code>CertPathBuilder</code> to search for a CRL while simultaneously * searching for further certificates, for instance. * <p> * This is achieved by adding the <code>synchronized</code> keyword to the * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods. * <p> * This classes uses caching and requests multiple attributes at once to * minimize LDAP round trips. The cache is associated with the CertStore * instance. It uses soft references to hold the values to minimize impact * on footprint and currently has a maximum size of 750 attributes and a * 30 second default lifetime. * <p> * We always request CA certificates, cross certificate pairs, and ARLs in * a single LDAP request when any one of them is needed. The reason is that * we typically need all of them anyway and requesting them in one go can * reduce the number of requests to a third. Even if we don't need them, * these attributes are typically small enough not to cause a noticeable * overhead. In addition, when the prefetchCRLs flag is true, we also request * the full CRLs. It is currently false initially but set to true once any * request for an ARL to the server returns an null value. The reason is * that CRLs could be rather large but are rarely used. This implementation * should improve performance in most cases. * * @see java.security.cert.CertStore * * @since 1.4 * @author Steve Hanna * @author Andreas Sterbenz */public class LDAPCertStore extends CertStoreSpi { private static final Debug debug = Debug.getInstance("certpath"); private final static boolean DEBUG = false; /** * LDAP attribute identifiers. */ private static final String USER_CERT = "userCertificate;binary"; private static final String CA_CERT = "cACertificate;binary"; private static final String CROSS_CERT = "crossCertificatePair;binary"; private static final String CRL = "certificateRevocationList;binary"; private static final String ARL = "authorityRevocationList;binary"; private static final String DELTA_CRL = "deltaRevocationList;binary"; // Constants for various empty values private final static String[] STRING0 = new String[0]; private final static byte[][] BB0 = new byte[0][]; private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes(); // cache related constants private final static int DEFAULT_CACHE_SIZE = 750; private final static int DEFAULT_CACHE_LIFETIME = 30; private final static int LIFETIME; private final static String PROP_LIFETIME = "sun.security.certpath.ldap.cache.lifetime"; static { String s = AccessController.doPrivileged( new GetPropertyAction(PROP_LIFETIME)); if (s != null) { LIFETIME = Integer.parseInt(s); // throws NumberFormatException } else { LIFETIME = DEFAULT_CACHE_LIFETIME; } } /** * The CertificateFactory used to decode certificates from * their binary stored form. */ private CertificateFactory cf; /** * The JNDI directory context. */ private DirContext ctx; /** * Flag indicating whether we should prefetch CRLs. */ private boolean prefetchCRLs = false; private final Cache valueCache; private int cacheHits = 0; private int cacheMisses = 0; private int requests = 0; /** * Creates a <code>CertStore</code> with the specified parameters. * For this class, the parameters object must be an instance of * <code>LDAPCertStoreParameters</code>. * * @param params the algorithm parameters * @exception InvalidAlgorithmParameterException if params is not an * instance of <code>LDAPCertStoreParameters</code> */ public LDAPCertStore(CertStoreParameters params) throws InvalidAlgorithmParameterException { super(params); if (!(params instanceof LDAPCertStoreParameters)) throw new InvalidAlgorithmParameterException( "parameters must be LDAPCertStoreParameters"); LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params; // Create InitialDirContext needed to communicate with the server createInitialDirContext(lparams.getServerName(), lparams.getPort()); // Create CertificateFactory for use later on try { cf = CertificateFactory.getInstance("X.509"); } catch (CertificateException e) { throw new InvalidAlgorithmParameterException( "unable to create CertificateFactory for X.509"); } if (LIFETIME == 0) { valueCache = Cache.newNullCache(); } else if (LIFETIME < 0) { valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE); } else { valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME); } } /** * Returns an LDAP CertStore. This method consults a cache of * CertStores (shared per JVM) using the LDAP server/port as a key. */ private static final Cache certStoreCache = Cache.newSoftMemoryCache(185); static synchronized CertStore getInstance(LDAPCertStoreParameters params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { CertStore lcs = (CertStore) certStoreCache.get(params); if (lcs == null) { lcs = CertStore.getInstance("LDAP", params); certStoreCache.put(params, lcs); } else { if (debug != null) { debug.println("LDAPCertStore.getInstance: cache hit"); } } return lcs; } /** * Create InitialDirContext. * * @param server Server DNS name hosting LDAP service * @param port Port at which server listens for requests * @throws InvalidAlgorithmParameterException if creation fails */ private void createInitialDirContext(String server, int port) throws InvalidAlgorithmParameterException { String url = "ldap://" + server + ":" + port; Hashtable<String,Object> env = new Hashtable<String,Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, url); try { ctx = new InitialDirContext(env); /* * By default, follow referrals unless application has * overridden property in an application resource file. */ Hashtable<?,?> currentEnv = ctx.getEnvironment(); if (currentEnv.get(Context.REFERRAL) == null) { ctx.addToEnvironment(Context.REFERRAL, "follow"); } } catch (NamingException e) { if (debug != null) { debug.println("LDAPCertStore.engineInit about to throw " + "InvalidAlgorithmParameterException"); e.printStackTrace(); } Exception ee = new InvalidAlgorithmParameterException ("unable to create InitialDirContext using supplied parameters"); ee.initCause(e); throw (InvalidAlgorithmParameterException)ee; } } /** * Private class encapsulating the actual LDAP operations and cache * handling. Use: * * LDAPRequest request = new LDAPRequest(dn); * request.addRequestedAttribute(CROSS_CERT); * request.addRequestedAttribute(CA_CERT); * byte[][] crossValues = request.getValues(CROSS_CERT); * byte[][] caValues = request.getValues(CA_CERT); * * At most one LDAP request is sent for each instance created. If all * getValues() calls can be satisfied from the cache, no request * is sent at all. If a request is sent, all requested attributes * are always added to the cache irrespective of whether the getValues() * method is called. */ private class LDAPRequest { private final String name; private Map<String, byte[][]> valueMap; private final List<String> requestedAttributes; LDAPRequest(String name) { this.name = name; requestedAttributes = new ArrayList<String>(5); } String getName() { return name; } void addRequestedAttribute(String attrId) { if (valueMap != null) { throw new IllegalStateException("Request already sent"); } requestedAttributes.add(attrId); } /** * Gets one or more binary values from an attribute. * * @param name the location holding the attribute * @param attrId the attribute identifier * @return an array of binary values (byte arrays) * @throws NamingException if a naming exception occurs */ byte[][] getValues(String attrId) throws NamingException { if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) { System.out.println("Cache hits: " + cacheHits + "; misses: " + cacheMisses); } String cacheKey = name + "|" + attrId; byte[][] values = (byte[][])valueCache.get(cacheKey); if (values != null) { cacheHits++; return values; } cacheMisses++; Map<String, byte[][]> attrs = getValueMap(); values = attrs.get(attrId); return values; } /** * Get a map containing the values for this request. The first time * this method is called on an object, the LDAP request is sent, * the results parsed and added to a private map and also to the * cache of this LDAPCertStore. Subsequent calls return the private * map immediately. * * The map contains an entry for each requested attribute. The * attribute name is the key, values are byte[][]. If there are no * values for that attribute, values are byte[0][]. * * @return the value Map * @throws NamingException if a naming exception occurs */ private Map<String, byte[][]> getValueMap() throws NamingException { if (valueMap != null) { return valueMap; } if (DEBUG) { System.out.println("Request: " + name + ":" + requestedAttributes); requests++; if (requests % 5 == 0) { System.out.println("LDAP requests: " + requests); } } valueMap = new HashMap<String, byte[][]>(8); String[] attrIds = requestedAttributes.toArray(STRING0); Attributes attrs; try { attrs = ctx.getAttributes(name, attrIds); } catch (NameNotFoundException e) { // name does not exist on this LDAP server // treat same as not attributes found attrs = EMPTY_ATTRIBUTES; } for (String attrId : requestedAttributes) { Attribute attr = attrs.get(attrId); byte[][] values = getAttributeValues(attr); cacheAttribute(attrId, values); valueMap.put(attrId, values); } return valueMap; } /** * Add the values to the cache. */ private void cacheAttribute(String attrId, byte[][] values) { String cacheKey = name + "|" + attrId; valueCache.put(cacheKey, values); } /** * Get the values for the given attribute. If the attribute is null * or does not contain any values, a zero length byte array is * returned. NOTE that it is assumed that all values are byte arrays. */ private byte[][] getAttributeValues(Attribute attr) throws NamingException { byte[][] values; if (attr == null) { values = BB0; } else { values = new byte[attr.size()][]; int i = 0; NamingEnumeration<?> enum_ = attr.getAll(); while (enum_.hasMore()) { Object obj = enum_.next(); if (debug != null) { if (obj instanceof String) { debug.println("LDAPCertStore.getAttrValues() " + "enum.next is a string!: " + obj); } } byte[] value = (byte[])obj; values[i++] = value; } } return values; } } /* * Gets certificates from an attribute id and location in the LDAP * directory. Returns a Collection containing only the Certificates that * match the specified CertSelector. * * @param name the location holding the attribute * @param id the attribute identifier * @param sel a CertSelector that the Certificates must match * @return a Collection of Certificates found * @throws CertStoreException if an exception occurs */ private Collection<X509Certificate> getCertificates(LDAPRequest request, String id, X509CertSelector sel) throws CertStoreException { /* fetch encoded certs from storage */ byte[][] encodedCert; try { encodedCert = request.getValues(id); } catch (NamingException namingEx) { throw new CertStoreException(namingEx); } int n = encodedCert.length; if (n == 0) { return Collections.<X509Certificate>emptySet(); } List<X509Certificate> certs = new ArrayList<X509Certificate>(n); /* decode certs and check if they satisfy selector */ for (int i = 0; i < n; i++) { ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]); try { Certificate cert = cf.generateCertificate(bais); if (sel.match(cert)) { certs.add((X509Certificate)cert); } } catch (CertificateException e) { if (debug != null) { debug.println("LDAPCertStore.getCertificates() encountered " + "exception while parsing cert, skipping the bad data: "); HexDumpEncoder encoder = new HexDumpEncoder(); debug.println( "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]"); } } } return certs; } /* * Gets certificate pairs from an attribute id and location in the LDAP * directory. * * @param name the location holding the attribute * @param id the attribute identifier * @return a Collection of X509CertificatePairs found * @throws CertStoreException if an exception occurs */ private Collection<X509CertificatePair> getCertPairs( LDAPRequest request, String id) throws CertStoreException { /* fetch the encoded cert pairs from storage */ byte[][] encodedCertPair; try { encodedCertPair = request.getValues(id); } catch (NamingException namingEx) { throw new CertStoreException(namingEx); } int n = encodedCertPair.length; if (n == 0) { return Collections.<X509CertificatePair>emptySet(); } List<X509CertificatePair> certPairs = new ArrayList<X509CertificatePair>(n); /* decode each cert pair and add it to the Collection */ for (int i = 0; i < n; i++) { try { X509CertificatePair certPair = X509CertificatePair.generateCertificatePair(encodedCertPair[i]); certPairs.add(certPair); } catch (CertificateException e) { if (debug != null) { debug.println( "LDAPCertStore.getCertPairs() encountered exception " + "while parsing cert, skipping the bad data: "); HexDumpEncoder encoder = new HexDumpEncoder(); debug.println( "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]"); } }Lines 1–500 of 1066. Load more
/* * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.provider.certpath.ldap; import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.net.URI; import java.util.*; import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NameNotFoundException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import java.security.*; import java.security.cert.Certificate; import java.security.cert.*; import javax.security.auth.x500.X500Principal; import sun.misc.HexDumpEncoder; import sun.security.provider.certpath.X509CertificatePair; import sun.security.util.Cache; import sun.security.util.Debug; import sun.security.x509.X500Name; import sun.security.action.GetPropertyAction; /** * A <code>CertStore</code> that retrieves <code>Certificates</code> and * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema * (RFC 2587): * <a href="http://www.ietf.org/rfc/rfc2587.txt"> * http://www.ietf.org/rfc/rfc2587.txt</a>. * <p> * Before calling the {@link #engineGetCertificates engineGetCertificates} or * {@link #engineGetCRLs engineGetCRLs} methods, the * {@link #LDAPCertStore(CertStoreParameters) * LDAPCertStore(CertStoreParameters)} constructor is called to create the * <code>CertStore</code> and establish the DNS name and port of the LDAP * server from which <code>Certificate</code>s and <code>CRL</code>s will be * retrieved. * <p> * <b>Concurrent Access</b> * <p> * As described in the javadoc for <code>CertStoreSpi</code>, the * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods * must be thread-safe. That is, multiple threads may concurrently * invoke these methods on a single <code>LDAPCertStore</code> object * (or more than one) with no ill effects. This allows a * <code>CertPathBuilder</code> to search for a CRL while simultaneously * searching for further certificates, for instance. * <p> * This is achieved by adding the <code>synchronized</code> keyword to the * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods. * <p> * This classes uses caching and requests multiple attributes at once to * minimize LDAP round trips. The cache is associated with the CertStore * instance. It uses soft references to hold the values to minimize impact * on footprint and currently has a maximum size of 750 attributes and a * 30 second default lifetime. * <p> * We always request CA certificates, cross certificate pairs, and ARLs in * a single LDAP request when any one of them is needed. The reason is that * we typically need all of them anyway and requesting them in one go can * reduce the number of requests to a third. Even if we don't need them, * these attributes are typically small enough not to cause a noticeable * overhead. In addition, when the prefetchCRLs flag is true, we also request * the full CRLs. It is currently false initially but set to true once any * request for an ARL to the server returns an null value. The reason is * that CRLs could be rather large but are rarely used. This implementation * should improve performance in most cases. * * @see java.security.cert.CertStore * * @since 1.4 * @author Steve Hanna * @author Andreas Sterbenz */ public class LDAPCertStore extends CertStoreSpi { private static final Debug debug = Debug.getInstance("certpath"); private final static boolean DEBUG = false; /** * LDAP attribute identifiers. */ private static final String USER_CERT = "userCertificate;binary"; private static final String CA_CERT = "cACertificate;binary"; private static final String CROSS_CERT = "crossCertificatePair;binary"; private static final String CRL = "certificateRevocationList;binary"; private static final String ARL = "authorityRevocationList;binary"; private static final String DELTA_CRL = "deltaRevocationList;binary"; // Constants for various empty values private final static String[] STRING0 = new String[0]; private final static byte[][] BB0 = new byte[0][]; private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes(); // cache related constants private final static int DEFAULT_CACHE_SIZE = 750; private final static int DEFAULT_CACHE_LIFETIME = 30; private final static int LIFETIME; private final static String PROP_LIFETIME = "sun.security.certpath.ldap.cache.lifetime"; static { String s = AccessController.doPrivileged( new GetPropertyAction(PROP_LIFETIME)); if (s != null) { LIFETIME = Integer.parseInt(s); // throws NumberFormatException } else { LIFETIME = DEFAULT_CACHE_LIFETIME; } } /** * The CertificateFactory used to decode certificates from * their binary stored form. */ private CertificateFactory cf; /** * The JNDI directory context. */ private DirContext ctx; /** * Flag indicating whether we should prefetch CRLs. */ private boolean prefetchCRLs = false; private final Cache valueCache; private int cacheHits = 0; private int cacheMisses = 0; private int requests = 0; /** * Creates a <code>CertStore</code> with the specified parameters. * For this class, the parameters object must be an instance of * <code>LDAPCertStoreParameters</code>. * * @param params the algorithm parameters * @exception InvalidAlgorithmParameterException if params is not an * instance of <code>LDAPCertStoreParameters</code> */ public LDAPCertStore(CertStoreParameters params) throws InvalidAlgorithmParameterException { super(params); if (!(params instanceof LDAPCertStoreParameters)) throw new InvalidAlgorithmParameterException( "parameters must be LDAPCertStoreParameters"); LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params; // Create InitialDirContext needed to communicate with the server createInitialDirContext(lparams.getServerName(), lparams.getPort()); // Create CertificateFactory for use later on try { cf = CertificateFactory.getInstance("X.509"); } catch (CertificateException e) { throw new InvalidAlgorithmParameterException( "unable to create CertificateFactory for X.509"); } if (LIFETIME == 0) { valueCache = Cache.newNullCache(); } else if (LIFETIME < 0) { valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE); } else { valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME); } } /** * Returns an LDAP CertStore. This method consults a cache of * CertStores (shared per JVM) using the LDAP server/port as a key. */ private static final Cache certStoreCache = Cache.newSoftMemoryCache(185); static synchronized CertStore getInstance(LDAPCertStoreParameters params) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { CertStore lcs = (CertStore) certStoreCache.get(params); if (lcs == null) { lcs = CertStore.getInstance("LDAP", params); certStoreCache.put(params, lcs); } else { if (debug != null) { debug.println("LDAPCertStore.getInstance: cache hit"); } } return lcs; } /** * Create InitialDirContext. * * @param server Server DNS name hosting LDAP service * @param port Port at which server listens for requests * @throws InvalidAlgorithmParameterException if creation fails */ private void createInitialDirContext(String server, int port) throws InvalidAlgorithmParameterException { String url = "ldap://" + server + ":" + port; Hashtable<String,Object> env = new Hashtable<String,Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, url); try { ctx = new InitialDirContext(env); /* * By default, follow referrals unless application has * overridden property in an application resource file. */ Hashtable<?,?> currentEnv = ctx.getEnvironment(); if (currentEnv.get(Context.REFERRAL) == null) { ctx.addToEnvironment(Context.REFERRAL, "follow"); } } catch (NamingException e) { if (debug != null) { debug.println("LDAPCertStore.engineInit about to throw " + "InvalidAlgorithmParameterException"); e.printStackTrace(); } Exception ee = new InvalidAlgorithmParameterException ("unable to create InitialDirContext using supplied parameters"); ee.initCause(e); throw (InvalidAlgorithmParameterException)ee; } } /** * Private class encapsulating the actual LDAP operations and cache * handling. Use: * * LDAPRequest request = new LDAPRequest(dn); * request.addRequestedAttribute(CROSS_CERT); * request.addRequestedAttribute(CA_CERT); * byte[][] crossValues = request.getValues(CROSS_CERT); * byte[][] caValues = request.getValues(CA_CERT); * * At most one LDAP request is sent for each instance created. If all * getValues() calls can be satisfied from the cache, no request * is sent at all. If a request is sent, all requested attributes * are always added to the cache irrespective of whether the getValues() * method is called. */ private class LDAPRequest { private final String name; private Map<String, byte[][]> valueMap; private final List<String> requestedAttributes; LDAPRequest(String name) { this.name = name; requestedAttributes = new ArrayList<String>(5); } String getName() { return name; } void addRequestedAttribute(String attrId) { if (valueMap != null) { throw new IllegalStateException("Request already sent"); } requestedAttributes.add(attrId); } /** * Gets one or more binary values from an attribute. * * @param name the location holding the attribute * @param attrId the attribute identifier * @return an array of binary values (byte arrays) * @throws NamingException if a naming exception occurs */ byte[][] getValues(String attrId) throws NamingException { if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) { System.out.println("Cache hits: " + cacheHits + "; misses: " + cacheMisses); } String cacheKey = name + "|" + attrId; byte[][] values = (byte[][])valueCache.get(cacheKey); if (values != null) { cacheHits++; return values; } cacheMisses++; Map<String, byte[][]> attrs = getValueMap(); values = attrs.get(attrId); return values; } /** * Get a map containing the values for this request. The first time * this method is called on an object, the LDAP request is sent, * the results parsed and added to a private map and also to the * cache of this LDAPCertStore. Subsequent calls return the private * map immediately. * * The map contains an entry for each requested attribute. The * attribute name is the key, values are byte[][]. If there are no * values for that attribute, values are byte[0][]. * * @return the value Map * @throws NamingException if a naming exception occurs */ private Map<String, byte[][]> getValueMap() throws NamingException { if (valueMap != null) { return valueMap; } if (DEBUG) { System.out.println("Request: " + name + ":" + requestedAttributes); requests++; if (requests % 5 == 0) { System.out.println("LDAP requests: " + requests); } } valueMap = new HashMap<String, byte[][]>(8); String[] attrIds = requestedAttributes.toArray(STRING0); Attributes attrs; try { attrs = ctx.getAttributes(name, attrIds); } catch (NameNotFoundException e) { // name does not exist on this LDAP server // treat same as not attributes found attrs = EMPTY_ATTRIBUTES; } for (String attrId : requestedAttributes) { Attribute attr = attrs.get(attrId); byte[][] values = getAttributeValues(attr); cacheAttribute(attrId, values); valueMap.put(attrId, values); } return valueMap; } /** * Add the values to the cache. */ private void cacheAttribute(String attrId, byte[][] values) { String cacheKey = name + "|" + attrId; valueCache.put(cacheKey, values); } /** * Get the values for the given attribute. If the attribute is null * or does not contain any values, a zero length byte array is * returned. NOTE that it is assumed that all values are byte arrays. */ private byte[][] getAttributeValues(Attribute attr) throws NamingException { byte[][] values; if (attr == null) { values = BB0; } else { values = new byte[attr.size()][]; int i = 0; NamingEnumeration<?> enum_ = attr.getAll(); while (enum_.hasMore()) { Object obj = enum_.next(); if (debug != null) { if (obj instanceof String) { debug.println("LDAPCertStore.getAttrValues() " + "enum.next is a string!: " + obj); } } byte[] value = (byte[])obj; values[i++] = value; } } return values; } } /* * Gets certificates from an attribute id and location in the LDAP * directory. Returns a Collection containing only the Certificates that * match the specified CertSelector. * * @param name the location holding the attribute * @param id the attribute identifier * @param sel a CertSelector that the Certificates must match * @return a Collection of Certificates found * @throws CertStoreException if an exception occurs */ private Collection<X509Certificate> getCertificates(LDAPRequest request, String id, X509CertSelector sel) throws CertStoreException { /* fetch encoded certs from storage */ byte[][] encodedCert; try { encodedCert = request.getValues(id); } catch (NamingException namingEx) { throw new CertStoreException(namingEx); } int n = encodedCert.length; if (n == 0) { return Collections.<X509Certificate>emptySet(); } List<X509Certificate> certs = new ArrayList<X509Certificate>(n); /* decode certs and check if they satisfy selector */ for (int i = 0; i < n; i++) { ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]); try { Certificate cert = cf.generateCertificate(bais); if (sel.match(cert)) { certs.add((X509Certificate)cert); } } catch (CertificateException e) { if (debug != null) { debug.println("LDAPCertStore.getCertificates() encountered " + "exception while parsing cert, skipping the bad data: "); HexDumpEncoder encoder = new HexDumpEncoder(); debug.println( "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]"); } } } return certs; } /* * Gets certificate pairs from an attribute id and location in the LDAP * directory. * * @param name the location holding the attribute * @param id the attribute identifier * @return a Collection of X509CertificatePairs found * @throws CertStoreException if an exception occurs */ private Collection<X509CertificatePair> getCertPairs( LDAPRequest request, String id) throws CertStoreException { /* fetch the encoded cert pairs from storage */ byte[][] encodedCertPair; try { encodedCertPair = request.getValues(id); } catch (NamingException namingEx) { throw new CertStoreException(namingEx); } int n = encodedCertPair.length; if (n == 0) { return Collections.<X509CertificatePair>emptySet(); } List<X509CertificatePair> certPairs = new ArrayList<X509CertificatePair>(n); /* decode each cert pair and add it to the Collection */ for (int i = 0; i < n; i++) { try { X509CertificatePair certPair = X509CertificatePair.generateCertificatePair(encodedCertPair[i]); certPairs.add(certPair); } catch (CertificateException e) { if (debug != null) { debug.println( "LDAPCertStore.getCertPairs() encountered exception " + "while parsing cert, skipping the bad data: "); HexDumpEncoder encoder = new HexDumpEncoder(); debug.println( "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]"); } }