diff options
author | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-24 02:27:47 -0500 |
---|---|---|
committer | Endi Sukma Dewata <edewata@redhat.com> | 2012-03-26 11:43:54 -0500 |
commit | 621d9e5c413e561293d7484b93882d985b3fe15f (patch) | |
tree | 638f3d75761c121d9a8fb50b52a12a6686c5ac5c /base/common/src/com/netscape/cmscore/dbs | |
parent | 40d3643b8d91886bf210aa27f711731c81a11e49 (diff) | |
download | pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.gz pki-621d9e5c413e561293d7484b93882d985b3fe15f.tar.xz pki-621d9e5c413e561293d7484b93882d985b3fe15f.zip |
Removed unnecessary pki folder.
Previously the source code was located inside a pki folder.
This folder was created during svn migration and is no longer
needed. This folder has now been removed and the contents have
been moved up one level.
Ticket #131
Diffstat (limited to 'base/common/src/com/netscape/cmscore/dbs')
40 files changed, 10323 insertions, 0 deletions
diff --git a/base/common/src/com/netscape/cmscore/dbs/BigIntegerMapper.java b/base/common/src/com/netscape/cmscore/dbs/BigIntegerMapper.java new file mode 100644 index 000000000..3fa613198 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/BigIntegerMapper.java @@ -0,0 +1,121 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java BigInteger object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class BigIntegerMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs BigInteger mapper. + */ + public BigIntegerMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Returns a list of supported ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object into ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + BigIntegerToDB((BigInteger) obj))); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + parent.set(name, BigIntegerFromDB( + (String) attr.getStringValues().nextElement())); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + String v = null; + + try { + if (value.startsWith("0x") || value.startsWith("0X")) { + v = BigIntegerToDB(new + BigInteger(value.substring(2), 16)); + } else { + v = BigIntegerToDB(new BigInteger(value)); + } + } catch (NumberFormatException e) { + v = value; + } + return mLdapName + op + v; + } + + public static String BigIntegerToDB(BigInteger i) { + int len = i.toString().length(); + String ret = null; + + if (len < 10) { + ret = "0" + Integer.toString(len) + i.toString(); + } else { + ret = Integer.toString(len) + i.toString(); + } + return ret; + } + + public static BigInteger BigIntegerFromDB(String i) { + String s = i.substring(2); + + // possibly check length + return new BigInteger(s); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/ByteArrayMapper.java b/base/common/src/com/netscape/cmscore/dbs/ByteArrayMapper.java new file mode 100644 index 000000000..38362f341 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/ByteArrayMapper.java @@ -0,0 +1,96 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java byte array object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class ByteArrayMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs a byte array mapper. + */ + public ByteArrayMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Lists a list of supported ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + byte data[] = (byte[]) obj; + if (data == null) { + CMS.debug("ByteArrayMapper:mapObjectToLDAPAttributeSet " + name + + " size=0"); + } else { + CMS.debug("ByteArrayMapper:mapObjectToLDAPAttributeSet " + name + + " size=" + data.length); + } + attrs.add(new LDAPAttribute(mLdapName, data)); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + parent.set(name, (byte[]) attr.getByteValues().nextElement()); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CRLDBSchema.java b/base/common/src/com/netscape/cmscore/dbs/CRLDBSchema.java new file mode 100644 index 000000000..253bd81e0 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CRLDBSchema.java @@ -0,0 +1,47 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +/** + * A class represents a collection of schema information + * for CRL. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CRLDBSchema { + + public static final String LDAP_OC_TOP = "top"; + public static final String LDAP_OC_CRL_RECORD = "crlIssuingPointRecord"; + public static final String LDAP_ATTR_CRL_ID = "cn"; + public static final String LDAP_ATTR_CRL_NUMBER = "crlNumber"; + public static final String LDAP_ATTR_DELTA_NUMBER = "deltaNumber"; + public static final String LDAP_ATTR_CRL_SIZE = "crlSize"; + public static final String LDAP_ATTR_DELTA_SIZE = "deltaSize"; + public static final String LDAP_ATTR_THIS_UPDATE = "thisUpdate"; + public static final String LDAP_ATTR_NEXT_UPDATE = "nextUpdate"; + public static final String LDAP_ATTR_FIRST_UNSAVED = "firstUnsaved"; + public static final String LDAP_ATTR_CRL = "certificateRevocationList"; + public static final String LDAP_ATTR_CA_CERT = "cACertificate"; + public static final String LDAP_ATTR_CRL_CACHE = "crlCache"; + public static final String LDAP_ATTR_REVOKED_CERTS = "revokedCerts"; + public static final String LDAP_ATTR_UNREVOKED_CERTS = "unrevokedCerts"; + public static final String LDAP_ATTR_EXPIRED_CERTS = "expiredCerts"; + public static final String LDAP_ATTR_DELTA_CRL = "deltaRevocationList"; +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CRLIssuingPointRecord.java b/base/common/src/com/netscape/cmscore/dbs/CRLIssuingPointRecord.java new file mode 100644 index 000000000..0a3a46f14 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CRLIssuingPointRecord.java @@ -0,0 +1,334 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.security.x509.RevokedCertificate; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; + +/** + * A class represents a CRL issuing point record. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CRLIssuingPointRecord implements ICRLIssuingPointRecord, IDBObj { + + /** + * + */ + private static final long serialVersionUID = 400565044343905267L; + protected String mId = null; // internal unique id + protected BigInteger mCRLNumber = null; // CRL number + protected Long mCRLSize = null; + protected Date mThisUpdate = null; + protected Date mNextUpdate = null; + protected BigInteger mDeltaCRLNumber = null; // delta CRL number + protected Long mDeltaCRLSize = null; + protected String mFirstUnsaved = null; + protected byte mCRL[] = null; + protected byte mCACert[] = null; + protected Hashtable<BigInteger, RevokedCertificate> mCRLCache = null; + protected Hashtable<BigInteger, RevokedCertificate> mRevokedCerts = null; + protected Hashtable<BigInteger, RevokedCertificate> mUnrevokedCerts = null; + protected Hashtable<BigInteger, RevokedCertificate> mExpiredCerts = null; + protected byte mDeltaCRL[] = null; + protected static Vector<String> mNames = new Vector<String>(); + static { + mNames.addElement(ATTR_ID); + mNames.addElement(ATTR_CRL_NUMBER); + mNames.addElement(ATTR_DELTA_NUMBER); + mNames.addElement(ATTR_CRL_SIZE); + mNames.addElement(ATTR_DELTA_SIZE); + mNames.addElement(ATTR_THIS_UPDATE); + mNames.addElement(ATTR_NEXT_UPDATE); + mNames.addElement(ATTR_FIRST_UNSAVED); + mNames.addElement(ATTR_CRL); + mNames.addElement(ATTR_CA_CERT); + mNames.addElement(ATTR_CRL_CACHE); + mNames.addElement(ATTR_REVOKED_CERTS); + mNames.addElement(ATTR_UNREVOKED_CERTS); + mNames.addElement(ATTR_EXPIRED_CERTS); + mNames.addElement(ATTR_DELTA_CRL); + } + + /** + * Constructs empty CRLIssuingPointRecord. This is + * required in database framework. + */ + public CRLIssuingPointRecord() { + } + + /** + * Constructs a CRLIssuingPointRecord + */ + public CRLIssuingPointRecord(String id, BigInteger crlNumber, Long crlSize, + Date thisUpdate, Date nextUpdate) { + mId = id; + mCRLNumber = crlNumber; + mCRLSize = crlSize; + mThisUpdate = thisUpdate; + mNextUpdate = nextUpdate; + mDeltaCRLNumber = BigInteger.ZERO; + mFirstUnsaved = NEW_CACHE; + mDeltaCRLSize = Long.valueOf(-1L); + mCRLCache = null; + mRevokedCerts = null; + mUnrevokedCerts = null; + mExpiredCerts = null; + } + + /** + * Constructs a CRLIssuingPointRecord + */ + public CRLIssuingPointRecord(String id, BigInteger crlNumber, Long crlSize, + Date thisUpdate, Date nextUpdate, BigInteger deltaCRLNumber, Long deltaCRLSize, + Hashtable<BigInteger, RevokedCertificate> revokedCerts, + Hashtable<BigInteger, RevokedCertificate> unrevokedCerts, + Hashtable<BigInteger, RevokedCertificate> expiredCerts) { + mId = id; + mCRLNumber = crlNumber; + mCRLSize = crlSize; + mThisUpdate = thisUpdate; + mNextUpdate = nextUpdate; + mDeltaCRLNumber = deltaCRLNumber; + mDeltaCRLSize = deltaCRLSize; + mFirstUnsaved = NEW_CACHE; + mCRLCache = null; + mRevokedCerts = revokedCerts; + mUnrevokedCerts = unrevokedCerts; + mExpiredCerts = expiredCerts; + } + + @SuppressWarnings({ "unchecked" }) + public void set(String name, Object obj) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_ID)) { + mId = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_CRL_NUMBER)) { + mCRLNumber = (BigInteger) obj; + } else if (name.equalsIgnoreCase(ATTR_CRL_SIZE)) { + mCRLSize = (Long) obj; + } else if (name.equalsIgnoreCase(ATTR_THIS_UPDATE)) { + mThisUpdate = (Date) obj; + } else if (name.equalsIgnoreCase(ATTR_NEXT_UPDATE)) { + mNextUpdate = (Date) obj; + } else if (name.equalsIgnoreCase(ATTR_DELTA_NUMBER)) { + mDeltaCRLNumber = (BigInteger) obj; + } else if (name.equalsIgnoreCase(ATTR_DELTA_SIZE)) { + mDeltaCRLSize = (Long) obj; + } else if (name.equalsIgnoreCase(ATTR_FIRST_UNSAVED)) { + mFirstUnsaved = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_CRL)) { + mCRL = (byte[]) obj; + } else if (name.equalsIgnoreCase(ATTR_CA_CERT)) { + mCACert = (byte[]) obj; + } else if (name.equalsIgnoreCase(ATTR_CRL_CACHE)) { + mCRLCache = (Hashtable<BigInteger, RevokedCertificate>) obj; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_CERTS)) { + mRevokedCerts = (Hashtable<BigInteger, RevokedCertificate>) obj; + } else if (name.equalsIgnoreCase(ATTR_UNREVOKED_CERTS)) { + mUnrevokedCerts = (Hashtable<BigInteger, RevokedCertificate>) obj; + } else if (name.equalsIgnoreCase(ATTR_EXPIRED_CERTS)) { + mExpiredCerts = (Hashtable<BigInteger, RevokedCertificate>) obj; + } else if (name.equalsIgnoreCase(ATTR_DELTA_CRL)) { + mDeltaCRL = (byte[]) obj; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + public Object get(String name) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_ID)) { + return mId; + } else if (name.equalsIgnoreCase(ATTR_CRL_NUMBER)) { + return mCRLNumber; + } else if (name.equalsIgnoreCase(ATTR_CRL_SIZE)) { + return mCRLSize; + } else if (name.equalsIgnoreCase(ATTR_THIS_UPDATE)) { + return mThisUpdate; + } else if (name.equalsIgnoreCase(ATTR_NEXT_UPDATE)) { + return mNextUpdate; + } else if (name.equalsIgnoreCase(ATTR_DELTA_NUMBER)) { + return mDeltaCRLNumber; + } else if (name.equalsIgnoreCase(ATTR_DELTA_SIZE)) { + return mDeltaCRLSize; + } else if (name.equalsIgnoreCase(ATTR_FIRST_UNSAVED)) { + return mFirstUnsaved; + } else if (name.equalsIgnoreCase(ATTR_CRL)) { + return mCRL; + } else if (name.equalsIgnoreCase(ATTR_CA_CERT)) { + return mCACert; + } else if (name.equalsIgnoreCase(ATTR_CRL_CACHE)) { + return mCRLCache; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_CERTS)) { + return mRevokedCerts; + } else if (name.equalsIgnoreCase(ATTR_UNREVOKED_CERTS)) { + return mUnrevokedCerts; + } else if (name.equalsIgnoreCase(ATTR_EXPIRED_CERTS)) { + return mExpiredCerts; + } else if (name.equalsIgnoreCase(ATTR_DELTA_CRL)) { + return mDeltaCRL; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + public void delete(String name) throws EBaseException { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + + public Enumeration<String> getElements() { + return mNames.elements(); + } + + public Enumeration<String> getSerializableAttrNames() { + return mNames.elements(); + } + + /** + * Retrieve unique CRL identifier. + */ + public String getId() { + return mId; + } + + /** + * Retrieves CRL number. + */ + public BigInteger getCRLNumber() { + return mCRLNumber; + } + + /** + * Retrieves CRL size. + */ + public Long getCRLSize() { + return mCRLSize; + } + + /** + * Retrieves this update time. + */ + public Date getThisUpdate() { + return mThisUpdate; + } + + /** + * Retrieves next update time. + */ + public Date getNextUpdate() { + return mNextUpdate; + } + + /** + * Retrieves delta CRL number. + */ + public BigInteger getDeltaCRLNumber() { + return mDeltaCRLNumber; + } + + /** + * Retrieves CRL size. + */ + public Long getDeltaCRLSize() { + return mDeltaCRLSize; + } + + /** + * Retrieve unique CRL identifier. + */ + public String getFirstUnsaved() { + return mFirstUnsaved; + } + + /** + * Retrieves CRL encodings. + */ + public byte[] getCRL() { + return mCRL; + } + + /** + * Retrieves CRL encodings. + */ + public byte[] getDeltaCRL() { + return mDeltaCRL; + } + + public byte[] getCACert() { + return mCACert; + } + + public Hashtable<BigInteger, RevokedCertificate> getCRLCacheNoClone() { + if (mCRLCache == null) + return null; + else + return mCRLCache; + } + + @SuppressWarnings("unchecked") + public Hashtable<BigInteger, RevokedCertificate> getCRLCache() { + if (mCRLCache == null) + return null; + else + return (Hashtable<BigInteger, RevokedCertificate>) mCRLCache.clone(); + } + + /** + * Retrieves cache info of revoked certificates. + */ + @SuppressWarnings("unchecked") + public Hashtable<BigInteger, RevokedCertificate> getRevokedCerts() { + if (mRevokedCerts == null) + return null; + else + return (Hashtable<BigInteger, RevokedCertificate>) mRevokedCerts.clone(); + } + + /** + * Retrieves cache info of unrevoked certificates. + */ + @SuppressWarnings("unchecked") + public Hashtable<BigInteger, RevokedCertificate> getUnrevokedCerts() { + if (mUnrevokedCerts == null) + return null; + else + return (Hashtable<BigInteger, RevokedCertificate>) mUnrevokedCerts.clone(); + } + + /** + * Retrieves cache info of expired certificates. + */ + @SuppressWarnings("unchecked") + public Hashtable<BigInteger, RevokedCertificate> getExpiredCerts() { + if (mExpiredCerts == null) + return null; + else + return (Hashtable<BigInteger, RevokedCertificate>) mExpiredCerts.clone(); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CRLRepository.java b/base/common/src/com/netscape/cmscore/dbs/CRLRepository.java new file mode 100644 index 000000000..7eb470d55 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CRLRepository.java @@ -0,0 +1,370 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.security.x509.RevokedCertificate; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; + +/** + * A class represents a CRL repository. It stores all the + * CRL issuing points. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CRLRepository extends Repository implements ICRLRepository { + + private final String mLdapCRLIssuingPointName = "cn"; + private IDBSubsystem mDBService; + private String mBaseDN; + + /** + * Constructs a CRL repository. + */ + public CRLRepository(IDBSubsystem dbService, int increment, String baseDN) + throws EDBException { + super(dbService, increment, baseDN); + mBaseDN = baseDN; + mDBService = dbService; + + /* + DBRegistry reg = dbService.getRegistry(); + String crlRecordOC[] = new String[1]; + crlRecordOC[0] = Schema.LDAP_OC_CRL_RECORD; + reg.registerObjectClass(CRLIssuingPointRecord.class.getName(), crlRecordOC); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_ID, + new StringMapper(Schema.LDAP_ATTR_CRL_ID)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL_NUMBER, + new BigIntegerMapper(Schema.LDAP_ATTR_CRL_NUMBER)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL_SIZE, + new LongMapper(Schema.LDAP_ATTR_CRL_SIZE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_THIS_UPDATE, + new DateMapper(Schema.LDAP_ATTR_THIS_UPDATE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_NEXT_UPDATE, + new DateMapper(Schema.LDAP_ATTR_NEXT_UPDATE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL, + new ByteArrayMapper(Schema.LDAP_ATTR_CRL)); + */ + } + + /** + * Retrieves backend database handle. + */ + public IDBSubsystem getDBSubsystem() { + return mDBService; + } + + /** + * Retrieves DN of this repository. + */ + public String getDN() { + return mBaseDN; + } + + /** + * Removes all objects with this repository. + */ + public void removeAllObjects() throws EBaseException { + } + + /** + * Adds CRL issuing points. + */ + public void addCRLIssuingPointRecord(ICRLIssuingPointRecord rec) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = mLdapCRLIssuingPointName + "=" + + ((CRLIssuingPointRecord) rec).getId().toString() + "," + getDN(); + + s.add(name, rec); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Retrieves all issuing points' names + */ + public Vector<String> getIssuingPointsNames() throws EBaseException { + IDBSSession s = mDBService.createSession(); + try { + String[] attrs = { ICRLIssuingPointRecord.ATTR_ID, "objectclass" }; + String filter = "objectclass=" + CMS.getCRLIssuingPointRecordName(); + IDBSearchResults res = s.search(getDN(), filter, attrs); + Vector<String> v = new Vector<String>(); + while (res.hasMoreElements()) { + ICRLIssuingPointRecord nextelement = + (ICRLIssuingPointRecord) res.nextElement(); + CMS.debug("CRLRepository getIssuingPointsNames(): name = " + + nextelement.getId()); + v.addElement(nextelement.getId()); + } + + return v; + } finally { + if (s != null) + s.close(); + } + } + + /** + * Reads issuing point record. + */ + public ICRLIssuingPointRecord readCRLIssuingPointRecord(String id) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + CRLIssuingPointRecord rec = null; + + try { + String name = mLdapCRLIssuingPointName + "=" + id + + "," + getDN(); + + if (s != null) { + rec = (CRLIssuingPointRecord) s.read(name); + } + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * deletes issuing point record. + */ + public void deleteCRLIssuingPointRecord(String id) + throws EBaseException { + IDBSSession s = null; + + try { + s = mDBService.createSession(); + String name = mLdapCRLIssuingPointName + "=" + id + + "," + getDN(); + + if (s != null) + s.delete(name); + } finally { + if (s != null) + s.close(); + } + } + + public void modifyCRLIssuingPointRecord(String id, + ModificationSet mods) throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = mLdapCRLIssuingPointName + "=" + id + + "," + getDN(); + + if (s != null) + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Updates CRL issuing point record. + */ + public void updateCRLIssuingPointRecord(String id, byte[] newCRL, + Date thisUpdate, Date nextUpdate, BigInteger crlNumber, Long crlSize) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + if (newCRL != null) { + mods.add(ICRLIssuingPointRecord.ATTR_CRL, + Modification.MOD_REPLACE, newCRL); + } + if (nextUpdate != null) { + mods.add(ICRLIssuingPointRecord.ATTR_NEXT_UPDATE, + Modification.MOD_REPLACE, nextUpdate); + } + mods.add(ICRLIssuingPointRecord.ATTR_THIS_UPDATE, + Modification.MOD_REPLACE, thisUpdate); + mods.add(ICRLIssuingPointRecord.ATTR_CRL_NUMBER, + Modification.MOD_REPLACE, crlNumber); + mods.add(ICRLIssuingPointRecord.ATTR_CRL_SIZE, + Modification.MOD_REPLACE, crlSize); + modifyCRLIssuingPointRecord(id, mods); + } + + /** + * Updates CRL issuing point record. + */ + public void updateCRLIssuingPointRecord(String id, byte[] newCRL, + Date thisUpdate, Date nextUpdate, BigInteger crlNumber, Long crlSize, + Hashtable<BigInteger, RevokedCertificate> revokedCerts, + Hashtable<BigInteger, RevokedCertificate> unrevokedCerts, + Hashtable<BigInteger, RevokedCertificate> expiredCerts) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + if (newCRL != null) { + mods.add(ICRLIssuingPointRecord.ATTR_CRL, + Modification.MOD_REPLACE, newCRL); + } + if (nextUpdate != null) { + mods.add(ICRLIssuingPointRecord.ATTR_NEXT_UPDATE, + Modification.MOD_REPLACE, nextUpdate); + } + mods.add(ICRLIssuingPointRecord.ATTR_THIS_UPDATE, + Modification.MOD_REPLACE, thisUpdate); + mods.add(ICRLIssuingPointRecord.ATTR_CRL_NUMBER, + Modification.MOD_REPLACE, crlNumber); + mods.add(ICRLIssuingPointRecord.ATTR_CRL_SIZE, + Modification.MOD_REPLACE, crlSize); + if (revokedCerts != null) { + mods.add(ICRLIssuingPointRecord.ATTR_REVOKED_CERTS, + Modification.MOD_REPLACE, revokedCerts); + } + if (unrevokedCerts != null) { + mods.add(ICRLIssuingPointRecord.ATTR_UNREVOKED_CERTS, + Modification.MOD_REPLACE, unrevokedCerts); + } + if (expiredCerts != null) { + mods.add(ICRLIssuingPointRecord.ATTR_EXPIRED_CERTS, + Modification.MOD_REPLACE, expiredCerts); + } + if (revokedCerts != null || unrevokedCerts != null) { + mods.add(ICRLIssuingPointRecord.ATTR_FIRST_UNSAVED, + Modification.MOD_REPLACE, ICRLIssuingPointRecord.CLEAN_CACHE); + } + modifyCRLIssuingPointRecord(id, mods); + } + + /** + * Updates CRL issuing point record with recently revoked certificates info. + */ + public void updateRevokedCerts(String id, + Hashtable<BigInteger, RevokedCertificate> revokedCerts, + Hashtable<BigInteger, RevokedCertificate> unrevokedCerts) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + mods.add(ICRLIssuingPointRecord.ATTR_REVOKED_CERTS, + Modification.MOD_REPLACE, revokedCerts); + mods.add(ICRLIssuingPointRecord.ATTR_UNREVOKED_CERTS, + Modification.MOD_REPLACE, unrevokedCerts); + mods.add(ICRLIssuingPointRecord.ATTR_FIRST_UNSAVED, + Modification.MOD_REPLACE, ICRLIssuingPointRecord.CLEAN_CACHE); + modifyCRLIssuingPointRecord(id, mods); + } + + /** + * Updates CRL issuing point record with recently expired certificates info. + */ + public void updateExpiredCerts(String id, Hashtable<BigInteger, RevokedCertificate> expiredCerts) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + mods.add(ICRLIssuingPointRecord.ATTR_EXPIRED_CERTS, + Modification.MOD_REPLACE, expiredCerts); + modifyCRLIssuingPointRecord(id, mods); + } + + /** + * Updates CRL issuing point record with CRL cache info. + */ + public void updateCRLCache(String id, Long crlSize, + Hashtable<BigInteger, RevokedCertificate> revokedCerts, + Hashtable<BigInteger, RevokedCertificate> unrevokedCerts, + Hashtable<BigInteger, RevokedCertificate> expiredCerts) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + if (crlSize != null) { + mods.add(ICRLIssuingPointRecord.ATTR_CRL_SIZE, + Modification.MOD_REPLACE, crlSize); + } + mods.add(ICRLIssuingPointRecord.ATTR_REVOKED_CERTS, + Modification.MOD_REPLACE, revokedCerts); + mods.add(ICRLIssuingPointRecord.ATTR_UNREVOKED_CERTS, + Modification.MOD_REPLACE, unrevokedCerts); + mods.add(ICRLIssuingPointRecord.ATTR_EXPIRED_CERTS, + Modification.MOD_REPLACE, expiredCerts); + mods.add(ICRLIssuingPointRecord.ATTR_FIRST_UNSAVED, + Modification.MOD_REPLACE, ICRLIssuingPointRecord.CLEAN_CACHE); + modifyCRLIssuingPointRecord(id, mods); + } + + /** + * Updates CRL issuing point record with delta-CRL. + */ + public void updateDeltaCRL(String id, BigInteger deltaCRLNumber, + Long deltaCRLSize, Date nextUpdate, + byte[] deltaCRL) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + if (deltaCRLNumber != null) { + mods.add(ICRLIssuingPointRecord.ATTR_DELTA_NUMBER, + Modification.MOD_REPLACE, deltaCRLNumber); + } + if (deltaCRLSize != null) { + mods.add(ICRLIssuingPointRecord.ATTR_DELTA_SIZE, + Modification.MOD_REPLACE, deltaCRLSize); + } + if (nextUpdate != null) { + mods.add(ICRLIssuingPointRecord.ATTR_NEXT_UPDATE, + Modification.MOD_REPLACE, nextUpdate); + } + if (deltaCRL != null) { + mods.add(ICRLIssuingPointRecord.ATTR_DELTA_CRL, + Modification.MOD_REPLACE, deltaCRL); + } + modifyCRLIssuingPointRecord(id, mods); + } + + public void updateFirstUnsaved(String id, String firstUnsaved) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + if (firstUnsaved != null) { + mods.add(ICRLIssuingPointRecord.ATTR_FIRST_UNSAVED, + Modification.MOD_REPLACE, firstUnsaved); + } + modifyCRLIssuingPointRecord(id, mods); + } + + public BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) + throws EBaseException { + + return null; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CertDBSchema.java b/base/common/src/com/netscape/cmscore/dbs/CertDBSchema.java new file mode 100644 index 000000000..67b662713 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CertDBSchema.java @@ -0,0 +1,54 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +/** + * A class represents a collection of certificate record + * specific schema information. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CertDBSchema { + + public static final String LDAP_OC_TOP = "top"; + public static final String LDAP_ATTR_META_INFO = "metaInfo"; + public static final String LDAP_ATTR_SERIALNO = "serialno"; + public static final String LDAP_ATTR_CREATE_TIME = "dateOfCreate"; + public static final String LDAP_ATTR_MODIFY_TIME = "dateOfModify"; + public static final String LDAP_ATTR_PUBLIC_KEY_DATA = "publicKeyData"; + + public static final String LDAP_OC_CERT_RECORD = "certificateRecord"; + public static final String LDAP_ATTR_CERT_RECORD_ID = "certRecordId"; + public static final String LDAP_ATTR_NOT_BEFORE = "notBefore"; + public static final String LDAP_ATTR_NOT_AFTER = "notAfter"; + public static final String LDAP_ATTR_SIGNED_CERT = "userCertificate"; + public static final String LDAP_ATTR_VERSION = "version"; + public static final String LDAP_ATTR_DURATION = "duration"; + public static final String LDAP_ATTR_SUBJECT = "subjectName"; + public static final String LDAP_ATTR_ALGORITHM = "algorithmId"; + public static final String LDAP_ATTR_SIGNING_ALGORITHM = "signingAlgorithmId"; + public static final String LDAP_ATTR_REVO_INFO = "revInfo"; + public static final String LDAP_ATTR_CERT_STATUS = "certStatus"; + public static final String LDAP_ATTR_AUTO_RENEW = "autoRenew"; + public static final String LDAP_ATTR_ISSUED_BY = "issuedBy"; + public static final String LDAP_ATTR_REVOKED_BY = "revokedBy"; + public static final String LDAP_ATTR_REVOKED_ON = "revokedOn"; + public static final String LDAP_ATTR_EXTENSION = "extension"; +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CertRecord.java b/base/common/src/com/netscape/cmscore/dbs/CertRecord.java new file mode 100644 index 000000000..1981757cb --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CertRecord.java @@ -0,0 +1,284 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.security.x509.X509CertImpl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; + +/** + * A class represents a serializable certificate record. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CertRecord implements IDBObj, ICertRecord { + + /** + * + */ + private static final long serialVersionUID = -6231895305929417777L; + private BigInteger mId = null; + private X509CertImpl mX509Certificate = null; + private String mStatus = null; + private String mAutoRenew = null; + private MetaInfo mMetaInfo = null; + // XXX revocationInfo not serializable + private transient RevocationInfo mRevocationInfo = null; + private Date mCreateTime = null; + private Date mModifyTime = null; + private String mIssuedBy = null; + private String mRevokedBy = null; + private Date mRevokedOn = null; + + protected static Vector<String> mNames = new Vector<String>(); + static { + mNames.addElement(ATTR_ID); + mNames.addElement(ATTR_META_INFO); + mNames.addElement(ATTR_REVO_INFO); + mNames.addElement(ATTR_X509CERT); + mNames.addElement(ATTR_CREATE_TIME); + mNames.addElement(ATTR_MODIFY_TIME); + mNames.addElement(ATTR_CERT_STATUS); + mNames.addElement(ATTR_AUTO_RENEW); + mNames.addElement(ATTR_ISSUED_BY); + mNames.addElement(ATTR_REVOKED_BY); + mNames.addElement(ATTR_REVOKED_ON); + } + + /** + * Constructs empty certificate record. + */ + public CertRecord() { + } + + /** + * Constructs certiificate record with certificate + * and meta info. + */ + public CertRecord(BigInteger id, Certificate cert, MetaInfo meta) { + mId = id; + if (cert instanceof X509CertImpl) + mX509Certificate = (X509CertImpl) cert; + mMetaInfo = meta; + mStatus = STATUS_VALID; + mAutoRenew = AUTO_RENEWAL_ENABLED; + mCreateTime = CMS.getCurrentDate(); + mModifyTime = CMS.getCurrentDate(); + } + + /** + * Sets attribute to this record. + */ + public void set(String name, Object obj) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_REVO_INFO)) { + mRevocationInfo = (RevocationInfo) obj; + } else if (name.equalsIgnoreCase(ATTR_ID)) { + mId = (BigInteger) obj; + } else if (name.equalsIgnoreCase(ATTR_META_INFO)) { + mMetaInfo = (MetaInfo) obj; + } else if (name.equalsIgnoreCase(ATTR_X509CERT)) { + mX509Certificate = (X509CertImpl) obj; + } else if (name.equalsIgnoreCase(ATTR_CERT_STATUS)) { + mStatus = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_AUTO_RENEW)) { + mAutoRenew = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_CREATE_TIME)) { + mCreateTime = (Date) obj; + } else if (name.equalsIgnoreCase(ATTR_MODIFY_TIME)) { + mModifyTime = (Date) obj; + } else if (name.equalsIgnoreCase(ATTR_ISSUED_BY)) { + mIssuedBy = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_BY)) { + mRevokedBy = (String) obj; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_ON)) { + mRevokedOn = (Date) obj; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Retrieves attributes from this record. + */ + public Object get(String name) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_REVO_INFO)) { + return mRevocationInfo; + } else if (name.equalsIgnoreCase(ATTR_ID)) { + return mId; + } else if (name.equalsIgnoreCase(ATTR_META_INFO)) { + return mMetaInfo; + } else if (name.equalsIgnoreCase(ATTR_X509CERT)) { + return mX509Certificate; + } else if (name.equalsIgnoreCase(ATTR_CERT_STATUS)) { + return mStatus; + } else if (name.equalsIgnoreCase(ATTR_AUTO_RENEW)) { + return mAutoRenew; + } else if (name.equalsIgnoreCase(ATTR_CREATE_TIME)) { + return mCreateTime; + } else if (name.equalsIgnoreCase(ATTR_MODIFY_TIME)) { + return mModifyTime; + } else if (name.equalsIgnoreCase(ATTR_ISSUED_BY)) { + return mIssuedBy; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_BY)) { + return mRevokedBy; + } else if (name.equalsIgnoreCase(ATTR_REVOKED_ON)) { + return mRevokedOn; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Deletes attribute from this record. + */ + public void delete(String name) throws EBaseException { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + + public Enumeration<String> getElements() { + return mNames.elements(); + } + + public Enumeration<String> getSerializableAttrNames() { + return mNames.elements(); + } + + /** + * Retrieves X509 certificate. + */ + public X509CertImpl getCertificate() { + return mX509Certificate; + } + + /** + * Retrieves meta information. + */ + public MetaInfo getMetaInfo() { + return mMetaInfo; + } + + /** + * Retrieves certificate status. + */ + public String getStatus() { + return mStatus; + } + + /** + * Retrieves the auto renew mode. + */ + public String getAutoRenew() { + return mAutoRenew; + } + + /** + * Retrieves revocation information. + */ + public IRevocationInfo getRevocationInfo() { + return mRevocationInfo; + } + + /** + * Retrieves serial number of this record. Usually, + * it is the same of the serial number of the + * associated certificate. + */ + public BigInteger getSerialNumber() { + return mId; + } + + /** + * Retrieves the person who issues this certificate. + */ + public String getIssuedBy() { + return mIssuedBy; + } + + /** + * Retrieves the person who revokes this certificate. + */ + public String getRevokedBy() { + return mRevokedBy; + } + + /** + * Retrieves the date which this record is revoked. + */ + public Date getRevokedOn() { + return mRevokedOn; + } + + /** + * Retrieves certificate serial number. + */ + public BigInteger getCertificateSerialNumber() { + return mX509Certificate.getSerialNumber(); + } + + /** + * Retrieves not after. + */ + public Date getNotAfter() { + return mX509Certificate.getNotAfter(); + } + + public Date getNotBefore() { + return mX509Certificate.getNotBefore(); + } + + /** + * Return revocation date. + */ + public Date getRevocationDate() throws EDBException { + return mRevocationInfo.getRevocationDate(); + } + + public Date getCreateTime() { + return mCreateTime; + } + + public Date getModifyTime() { + return mModifyTime; + } + + /** + * String representation + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + + buf.append("CertRecord: "); + if (getSerialNumber() != null) + buf.append(" " + getSerialNumber().toString()); + return buf.toString(); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CertRecordList.java b/base/common/src/com/netscape/cmscore/dbs/CertRecordList.java new file mode 100644 index 000000000..29792880d --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CertRecordList.java @@ -0,0 +1,113 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.IElementProcessor; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; + +/** + * A class represents a list of certificate records. + * <P> + * + * @author thomask mzhao + * @version $Revision$, $Date$ + */ +public class CertRecordList implements ICertRecordList { + + private IDBVirtualList<ICertRecord> mVlist = null; + + /** + * Constructs a request list. + */ + public CertRecordList(IDBVirtualList<ICertRecord> vlist) { + mVlist = vlist; + } + + public int getCurrentIndex() { + return mVlist.getCurrentIndex(); + } + + /** + * Retrieves the size of request list. + */ + public int getSize() { + // get the size of the virtual list + return mVlist.getSize(); + } + + public int getSizeBeforeJumpTo() { + return mVlist.getSizeBeforeJumpTo(); + + } + + public int getSizeAfterJumpTo() { + return mVlist.getSizeAfterJumpTo(); + + } + + /** + * Process certificate record as soon as it is returned. + * kmccarth: changed to ignore startidx and endidx because VLVs don't + * provide a stable list. + */ + public void processCertRecords(int startidx, int endidx, + IElementProcessor ep) throws EBaseException { + int i = 0; + while (i < mVlist.getSize()) { + Object element = mVlist.getElementAt(i); + if (element != null && (!(element instanceof String))) { + ep.process(element); + } + i++; + } + } + + /** + * Retrieves requests. + * It's no good to call this if you didnt check + * if the startidx, endidx are valid. + */ + public Enumeration<ICertRecord> getCertRecords(int startidx, int endidx) + throws EBaseException { + Vector<ICertRecord> entries = new Vector<ICertRecord>(); + + for (int i = startidx; i <= endidx; i++) { + ICertRecord element = mVlist.getElementAt(i); + + // CMS.debug("gerCertRecords[" + i + "] element: " + element); + if (element != null) { + entries.addElement(element); + } + } + return entries.elements(); + } + + public ICertRecord getCertRecord(int index) + throws EBaseException { + + return mVlist.getElementAt(index); + + } + +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CertRecordMapper.java b/base/common/src/com/netscape/cmscore/dbs/CertRecordMapper.java new file mode 100644 index 000000000..f4074c213 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CertRecordMapper.java @@ -0,0 +1,99 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.cmscore.util.Debug; + +/** + * A class represents a mapper to serialize + * certificate record into database. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class CertRecordMapper implements IDBAttrMapper { + + private ICertificateRepository mDB = null; + + public CertRecordMapper(ICertificateRepository db) { + mDB = db; + } + + public Enumeration<String> getSupportedLDAPAttributeNames() { + Vector<String> v = new Vector<String>(); + + v.addElement(CertDBSchema.LDAP_ATTR_CERT_RECORD_ID); + return v.elements(); + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) + throws EBaseException { + try { + CertRecord rec = (CertRecord) obj; + + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_CERT_RECORD_ID, + rec.getSerialNumber().toString())); + } catch (Exception e) { + Debug.trace(e.toString()); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_SERIALIZE_FAILED", name)); + } + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + try { + LDAPAttribute attr = attrs.getAttribute( + CertDBSchema.LDAP_ATTR_CERT_RECORD_ID); + + if (attr == null) + return; + String serialno = (String) attr.getStringValues().nextElement(); + ICertRecord rec = mDB.readCertificateRecord( + new BigInteger(serialno)); + + parent.set(name, rec); + } catch (Exception e) { + Debug.trace(e.toString()); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } + } + + public String mapSearchFilter(String name, String op, String value) + throws EBaseException { + return name + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java b/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java new file mode 100644 index 000000000..0df563cad --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/CertificateRepository.java @@ -0,0 +1,2030 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.io.Serializable; +import java.math.BigInteger; +import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPSearchResults; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.IElementProcessor; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +import com.netscape.certsrv.dbs.repository.IRepository; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents a certificate repository. It + * stores all the issued certificate. + * <P> + * + * @author thomask + * @author kanda + * @version $Revision$, $Date$ + */ +public class CertificateRepository extends Repository + implements ICertificateRepository { + + public final String CERT_X509ATTRIBUTE = "x509signedcert"; + + private IDBSubsystem mDBService; + private String mBaseDN; + private String mRequestBaseDN; + private boolean mConsistencyCheck = false; + private boolean mSkipIfInconsistent = false; + + private int mCertStatusUpdateInterval = 0; + private Hashtable<String, ICRLIssuingPoint> mCRLIssuingPoints = new Hashtable<String, ICRLIssuingPoint>(); + + private int mTransitMaxRecords = 1000000; + private int mTransitRecordPageSize = 200; + + CertStatusUpdateTask certStatusUpdateTask; + RetrieveModificationsTask retrieveModificationsTask; + + IRepository requestRepository; + + /** + * Constructs a certificate repository. + */ + public CertificateRepository(IDBSubsystem dbService, String certRepoBaseDN, int increment, String baseDN) + throws EDBException { + super(dbService, increment, baseDN); + mBaseDN = certRepoBaseDN; + mDBService = dbService; + } + + public ICertRecord createCertRecord(BigInteger id, Certificate cert, MetaInfo meta) { + return new CertRecord(id, cert, meta); + } + + public BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) + throws EBaseException { + + CMS.debug("CertificateRepository: in getLastSerialNumberInRange: low " + + serial_low_bound + " high " + serial_upper_bound); + + if (serial_low_bound == null + || serial_upper_bound == null || serial_low_bound.compareTo(serial_upper_bound) >= 0) { + return null; + + } + + String ldapfilter = "(" + "certstatus" + "=*" + ")"; + + String[] attrs = null; + + ICertRecordList recList = + findCertRecordsInList(ldapfilter, attrs, serial_upper_bound.toString(10), "serialno", 5 * -1); + + int size = recList.getSize(); + + CMS.debug("CertificateRepository:getLastSerialNumberInRange: recList size " + size); + + if (size <= 0) { + CMS.debug("CertificateRepository:getLastSerialNumberInRange: index may be empty"); + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret); + return ret; + } + int ltSize = recList.getSizeBeforeJumpTo(); + + CMS.debug("CertificateRepository:getLastSerialNumberInRange: ltSize " + ltSize); + + CertRecord curRec = null; + + int i; + Object obj = null; + + for (i = 0; i < 5; i++) { + obj = recList.getCertRecord(i); + + if (obj != null) { + curRec = (CertRecord) obj; + + BigInteger serial = curRec.getSerialNumber(); + + CMS.debug("CertificateRepository:getLastCertRecordSerialNo: serialno " + serial); + + if (((serial.compareTo(serial_low_bound) == 0) || (serial.compareTo(serial_low_bound) == 1)) && + ((serial.compareTo(serial_upper_bound) == 0) || (serial.compareTo(serial_upper_bound) == -1))) { + CMS.debug("getLastSerialNumberInRange returning: " + serial); + return serial; + } + } else { + CMS.debug("getLastSerialNumberInRange:found null from getCertRecord"); + } + } + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("CertificateRepository:getLastCertRecordSerialNo: returning " + ret); + return ret; + + } + + /** + * Removes all objects with this repository. + */ + public void removeCertRecords(BigInteger beginS, BigInteger endS) throws EBaseException { + String filter = "(" + CertRecord.ATTR_CERT_STATUS + "=*" + ")"; + ICertRecordList list = findCertRecordsInList(filter, + null, "serialno", 10); + int size = list.getSize(); + Enumeration<ICertRecord> e = list.getCertRecords(0, size - 1); + while (e.hasMoreElements()) { + CertRecord rec = (CertRecord) e.nextElement(); + BigInteger cur = rec.getSerialNumber(); + BigInteger max = cur.max(beginS); + BigInteger min = cur; + if (endS != null) + min = cur.min(endS); + if (cur.equals(beginS) || cur.equals(endS) || + (cur.equals(max) && cur.equals(min))) + deleteCertificateRecord(cur); + } + } + + public void setConsistencyCheck(boolean ConsistencyCheck) { + mConsistencyCheck = ConsistencyCheck; + } + + public void setSkipIfInConsistent(boolean SkipIfInconsistent) { + mSkipIfInconsistent = SkipIfInconsistent; + } + + public void setTransitMaxRecords(int max) { + mTransitMaxRecords = max; + } + + public void setTransitRecordPageSize(int size) { + mTransitRecordPageSize = size; + + } + + /** + * register CRL Issuing Point + */ + public void addCRLIssuingPoint(String id, ICRLIssuingPoint crlIssuingPoint) { + mCRLIssuingPoints.put(id, crlIssuingPoint); + } + + /** + * interval value: (in seconds) + * 0 - disable + * >0 - enable + */ + public void setCertStatusUpdateInterval(IRepository requestRepository, int interval, boolean listenToCloneModifications) { + + CMS.debug("In setCertStatusUpdateInterval " + interval); + + this.requestRepository = requestRepository; + + if (interval == 0) { + CMS.debug("In setCertStatusUpdateInterval interval = 0"); + if (certStatusUpdateTask != null) { + certStatusUpdateTask.stop(); + } + if (retrieveModificationsTask != null) { + retrieveModificationsTask.stop(); + } + return; + } + + CMS.debug("In setCertStatusUpdateInterval listenToCloneModifications=" + listenToCloneModifications); + + if (listenToCloneModifications) { + CMS.debug("In setCertStatusUpdateInterval listening to modifications"); + try { + retrieveModificationsTask = new RetrieveModificationsTask(this); + retrieveModificationsTask.start(); + } catch (EBaseException e) { + retrieveModificationsTask = null; + e.printStackTrace(); + } + } + + CMS.debug("In setCertStatusUpdateInterval scheduling cert status update every " + interval + " seconds."); + certStatusUpdateTask = new CertStatusUpdateTask(this, interval); + certStatusUpdateTask.start(); + } + + /** + * This method blocks when another thread (such as the CRL Update) is running + */ + public synchronized void updateCertStatus() { + + CMS.debug("In updateCertStatus()"); + + try { + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_START_VALID_SEARCH")); + transitInvalidCertificates(); + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_FINISH_VALID_SEARCH")); + + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_START_EXPIRED_SEARCH")); + transitValidCertificates(); + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_FINISH_EXPIRED_SEARCH")); + + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_START_REVOKED_EXPIRED_SEARCH")); + transitRevokedExpiredCertificates(); + CMS.getLogger().log(ILogger.EV_SYSTEM, ILogger.S_OTHER, + CMS.getLogMessage("CMSCORE_DBS_FINISH_REVOKED_EXPIRED_SEARCH")); + + CMS.debug("Starting cert checkRanges"); + checkRanges(); + CMS.debug("cert checkRanges done"); + + CMS.debug("Starting request checkRanges"); + requestRepository.checkRanges(); + CMS.debug("request checkRanges done"); + + } catch (Exception e) { + CMS.debug("updateCertStatus done: " + e.toString()); + } + } + + public synchronized void processRevokedCerts(IElementProcessor p, String filter, int pageSize) + throws EBaseException { + + CMS.debug("Starting processRevokedCerts (entered lock)"); + ICertRecordList list = findCertRecordsInList(filter, + new String[] { ICertRecord.ATTR_ID, ICertRecord.ATTR_REVO_INFO, "objectclass" }, + "serialno", + pageSize); + + int totalSize = list.getSize(); + + list.processCertRecords(0, totalSize - 1, p); + CMS.debug("processRevokedCerts done"); + } + + /** + * Retrieves DN of this repository. + */ + public String getDN() { + return mBaseDN; + } + + public void setRequestDN(String requestDN) { + mRequestBaseDN = requestDN; + } + + public String getRequestDN() { + return mRequestBaseDN; + } + + /** + * Retrieves backend database handle. + */ + public IDBSubsystem getDBSubsystem() { + return mDBService; + } + + /** + * Adds a certificate record to the repository. Each certificate + * record contains four parts: certificate, meta-attributes, + * issue information and reovcation information. + * <P> + * + * @param cert X.509 certificate + * @exception EBaseException failed to add new certificate to + * the repository + */ + public void addCertificateRecord(ICertRecord record) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + ((CertRecord) record).getSerialNumber().toString() + "," + getDN(); + SessionContext ctx = SessionContext.getContext(); + String uid = (String) ctx.get(SessionContext.USER_ID); + + if (uid == null) { + // XXX is this right? + record.set(CertRecord.ATTR_ISSUED_BY, "system"); + + /** + * System.out.println("XXX servlet should set USER_ID"); + * throw new EBaseException(BaseResources.UNKNOWN_PRINCIPAL_1, + * "null"); + **/ + } else { + record.set(CertRecord.ATTR_ISSUED_BY, uid); + } + + // Check validity of this certificate. If it is not invalid, + // mark it so. We will have a thread to transit the status + // from INVALID to VALID. + X509CertImpl x509cert = (X509CertImpl) record.get( + CertRecord.ATTR_X509CERT); + + if (x509cert != null) { + Date now = CMS.getCurrentDate(); + + if (x509cert.getNotBefore().after(now)) { + // not yet valid + record.set(ICertRecord.ATTR_CERT_STATUS, + ICertRecord.STATUS_INVALID); + } + } + + s.add(name, record); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Used by the Clone Master (CLA) to add a revoked certificate + * record to the repository. + * <p> + * + * @param record a CertRecord + * @exception EBaseException failed to add new certificate to + * the repository + */ + public void addRevokedCertRecord(CertRecord record) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + record.getSerialNumber().toString() + "," + getDN(); + + s.add(name, record); + } finally { + if (s != null) + s.close(); + } + } + + /** + * This transits a certificate status from VALID to EXPIRED + * if a certificate becomes expired. + */ + public void transitValidCertificates() throws EBaseException { + + Date now = CMS.getCurrentDate(); + ICertRecordList recList = getValidCertsByNotAfterDate(now, -1 * mTransitRecordPageSize); + + int size = recList.getSize(); + + if (size <= 0) { + CMS.debug("index may be empty"); + return; + } + int ltSize = recList.getSizeBeforeJumpTo(); + + ltSize = Math.min(ltSize, mTransitMaxRecords); + + Vector<Serializable> cList = new Vector<Serializable>(ltSize); + + CMS.debug("transidValidCertificates: list size: " + size); + CMS.debug("transitValidCertificates: ltSize " + ltSize); + + CertRecord curRec = null; + + int i; + ICertRecord obj = null; + + for (i = 0; i < ltSize; i++) { + obj = recList.getCertRecord(i); + + if (obj != null) { + curRec = (CertRecord) obj; + + Date notAfter = curRec.getNotAfter(); + + //CMS.debug("notAfter " + notAfter.toString() + " now " + now.toString()); + if (notAfter.after(now)) { + CMS.debug("Record does not qualify,notAfter " + notAfter.toString() + " date " + now.toString()); + continue; + } + + CMS.debug("transitValid: curRec: " + i + " " + curRec.toString()); + + if (mConsistencyCheck) { + cList.add(curRec); + } else { + cList.add(curRec.getSerialNumber()); + } + } else { + CMS.debug("found null from getCertRecord"); + } + } + + transitCertList(cList, CertRecord.STATUS_EXPIRED); + } + + /** + * This transits a certificate status from REVOKED to REVOKED_EXPIRED + * if an revoked certificate becomes expired. + */ + public void transitRevokedExpiredCertificates() throws EBaseException { + Date now = CMS.getCurrentDate(); + ICertRecordList recList = getRevokedCertsByNotAfterDate(now, -1 * mTransitRecordPageSize); + + int size = recList.getSize(); + + if (size <= 0) { + CMS.debug("index may be empty"); + return; + } + + int ltSize = recList.getSizeBeforeJumpTo(); + Vector<Serializable> cList = new Vector<Serializable>(ltSize); + + ltSize = Math.min(ltSize, mTransitMaxRecords); + + CMS.debug("transitRevokedExpiredCertificates: list size: " + size); + CMS.debug("transitRevokedExpiredCertificates: ltSize " + ltSize); + + CertRecord curRec = null; + int i; + Object obj = null; + + for (i = 0; i < ltSize; i++) { + obj = recList.getCertRecord(i); + if (obj != null) { + curRec = (CertRecord) obj; + CMS.debug("transitRevokedExpired: curRec: " + i + " " + curRec.toString()); + + Date notAfter = curRec.getNotAfter(); + + // CMS.debug("notAfter " + notAfter.toString() + " now " + now.toString()); + if (notAfter.after(now)) { + CMS.debug("Record does not qualify,notAfter " + notAfter.toString() + " date " + now.toString()); + continue; + } + + if (mConsistencyCheck) { + cList.add(curRec); + } else { + cList.add(curRec.getSerialNumber()); + } + } else { + CMS.debug("found null record in getCertRecord"); + } + } + + transitCertList(cList, CertRecord.STATUS_REVOKED_EXPIRED); + + } + + /** + * This transits a certificate status from INVALID to VALID + * if a certificate becomes valid. + */ + public void transitInvalidCertificates() throws EBaseException { + + Date now = CMS.getCurrentDate(); + + ICertRecordList recList = getInvalidCertsByNotBeforeDate(now, -1 * mTransitRecordPageSize); + + int size = recList.getSize(); + + if (size <= 0) { + CMS.debug("index may be empty"); + return; + } + int ltSize = recList.getSizeBeforeJumpTo(); + + ltSize = Math.min(ltSize, mTransitMaxRecords); + + Vector<Serializable> cList = new Vector<Serializable>(ltSize); + + CMS.debug("transidInValidCertificates: list size: " + size); + CMS.debug("transitInValidCertificates: ltSize " + ltSize); + + CertRecord curRec = null; + + int i; + + Object obj = null; + + for (i = 0; i < ltSize; i++) { + obj = recList.getCertRecord(i); + + if (obj != null) { + curRec = (CertRecord) obj; + + Date notBefore = curRec.getNotBefore(); + + //CMS.debug("notBefore " + notBefore.toString() + " now " + now.toString()); + if (notBefore.after(now)) { + CMS.debug("Record does not qualify,notBefore " + notBefore.toString() + " date " + now.toString()); + continue; + + } + CMS.debug("transitInValid: curRec: " + i + " " + curRec.toString()); + + if (mConsistencyCheck) { + cList.add(curRec); + } else { + cList.add(curRec.getSerialNumber()); + } + + } else { + CMS.debug("found null from getCertRecord"); + } + } + + transitCertList(cList, CertRecord.STATUS_VALID); + + } + + private void transitCertList(Vector<Serializable> cList, String newCertStatus) throws EBaseException { + CertRecord cRec = null; + BigInteger serial = null; + + int i; + + CMS.debug("transitCertList " + newCertStatus); + + for (i = 0; i < cList.size(); i++) { + if (mConsistencyCheck) { + cRec = (CertRecord) cList.elementAt(i); + + if (cRec == null) + continue; + + serial = cRec.getSerialNumber(); + } else { + serial = (BigInteger) cList.elementAt(i); + } + + updateStatus(serial, newCertStatus); + + if (newCertStatus.equals(CertRecord.STATUS_REVOKED_EXPIRED)) { + + // inform all CRLIssuingPoints about revoked and expired certificate + + Enumeration<ICRLIssuingPoint> eIPs = mCRLIssuingPoints.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = eIPs.nextElement(); + + if (ip != null) { + ip.addExpiredCert(serial); + } + } + + } + + CMS.debug("transitCertList number at: " + i + " = " + serial); + } + + cList.removeAllElements(); + } + + /** + * Reads the certificate identified by the given serial no. + */ + public X509CertImpl getX509Certificate(BigInteger serialNo) + throws EBaseException { + ICertRecord cr = readCertificateRecord(serialNo); + + return (cr.getCertificate()); + } + + /** + * Deletes certificate record. + */ + public void deleteCertificateRecord(BigInteger serialNo) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + s.delete(name); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Reads certificate from repository. + */ + public ICertRecord readCertificateRecord(BigInteger serialNo) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + CertRecord rec = null; + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + rec = (CertRecord) s.read(name); + } finally { + if (s != null) + s.close(); + } + return rec; + } + + public synchronized void modifyCertificateRecord(BigInteger serialNo, + ModificationSet mods) throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + mods.add(CertRecord.ATTR_MODIFY_TIME, Modification.MOD_REPLACE, + CMS.getCurrentDate()); + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Checks if the specified certificate is in the repository. + */ + public boolean containsCertificate(BigInteger serialNo) + throws EBaseException { + try { + ICertRecord cr = readCertificateRecord(serialNo); + + if (cr != null) + return true; + } catch (EBaseException e) { + } + return false; + } + + /** + * Marks certificate as revoked. + */ + public void markAsRevoked(BigInteger id, IRevocationInfo info) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + mods.add(CertRecord.ATTR_REVO_INFO, Modification.MOD_ADD, info); + SessionContext ctx = SessionContext.getContext(); + String uid = (String) ctx.get(SessionContext.USER_ID); + + if (uid == null) { + mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_ADD, + "system"); + } else { + mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_ADD, + uid); + } + mods.add(CertRecord.ATTR_REVOKED_ON, Modification.MOD_ADD, + CMS.getCurrentDate()); + mods.add(CertRecord.ATTR_CERT_STATUS, Modification.MOD_REPLACE, + CertRecord.STATUS_REVOKED); + modifyCertificateRecord(id, mods); + } + + /** + * Unmarks revoked certificate. + */ + public void unmarkRevoked(BigInteger id, IRevocationInfo info, + Date revokedOn, String revokedBy) + throws EBaseException { + ModificationSet mods = new ModificationSet(); + + mods.add(CertRecord.ATTR_REVO_INFO, Modification.MOD_DELETE, info); + mods.add(CertRecord.ATTR_REVOKED_BY, Modification.MOD_DELETE, revokedBy); + mods.add(CertRecord.ATTR_REVOKED_ON, Modification.MOD_DELETE, revokedOn); + mods.add(CertRecord.ATTR_CERT_STATUS, Modification.MOD_REPLACE, + CertRecord.STATUS_VALID); + modifyCertificateRecord(id, mods); + } + + /** + * Updates the certificiate record status to the specified. + */ + public void updateStatus(BigInteger id, String status) + throws EBaseException { + CMS.debug("updateStatus: " + id + " status " + status); + ModificationSet mods = new ModificationSet(); + + mods.add(CertRecord.ATTR_CERT_STATUS, Modification.MOD_REPLACE, + status); + modifyCertificateRecord(id, mods); + } + + public Enumeration<Object> searchCertificates(String filter, int maxSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<Object> e = null; + + CMS.debug("searchCertificates filter " + filter + " maxSize " + maxSize); + try { + e = s.search(getDN(), filter, maxSize); + } finally { + if (s != null) + s.close(); + } + return e; + } + + public Enumeration<ICertRecord> searchCertificates(String filter, int maxSize, int timeLimit) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<ICertRecord> v = new Vector<ICertRecord>(); + + CMS.debug("searchCertificateswith time limit filter " + filter); + try { + IDBSearchResults sr = s.search(getDN(), filter, maxSize, timeLimit); + while (sr.hasMoreElements()) { + v.add((ICertRecord) sr.nextElement()); + } + } finally { + if (s != null) + s.close(); + } + return v.elements(); + } + + /** + * Returns a list of X509CertImp that satisfies the filter. + * + * @deprecated replaced by <code>findCertificatesInList</code> + */ + public Enumeration<Object> findCertRecs(String filter) + throws EBaseException { + CMS.debug("findCertRecs " + filter); + IDBSSession s = mDBService.createSession(); + Enumeration<Object> e = null; + try { + e = s.search(getDN(), filter); + } finally { + if (s != null) + s.close(); + } + return e; + } + + public Enumeration<Object> findCertRecs(String filter, String[] attrs) + throws EBaseException { + + CMS.debug("findCertRecs " + filter + + "attrs " + Arrays.toString(attrs)); + IDBSSession s = mDBService.createSession(); + Enumeration<Object> e = null; + try { + e = s.search(getDN(), filter, attrs); + } finally { + if (s != null) + s.close(); + } + return e; + + } + + public Enumeration<X509CertImpl> findCertificates(String filter) + throws EBaseException { + Enumeration<ICertRecord> e = findCertRecords(filter); + Vector<X509CertImpl> v = new Vector<X509CertImpl>(); + + while (e.hasMoreElements()) { + ICertRecord rec = e.nextElement(); + + v.addElement(rec.getCertificate()); + } + return v.elements(); + } + + /** + * Finds a list of certificate records that satisifies + * the filter. + * If you are going to process everything in the list, + * use this. + */ + public Enumeration<ICertRecord> findCertRecords(String filter) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + //e = s.search(getDN(), filter); + ICertRecordList list = null; + + list = findCertRecordsInList(filter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + if (s != null) + s.close(); + } + return e; + } + + /** + * Finds certificate records. Here is a list of filter + * attribute can be used: + * + * <pre> + * certRecordId + * certMetaInfo + * certStatus + * certCreateTime + * certModifyTime + * x509Cert.notBefore + * x509Cert.notAfter + * x509Cert.subject + * </pre> + * + * The filter should follow RFC1558 LDAP filter syntax. + * For example, + * + * <pre> + * (&(certRecordId=5)(x509Cert.notBefore=934398398)) + * </pre> + */ + public ICertRecordList findCertRecordsInList(String filter, + String attrs[], int pageSize) throws EBaseException { + return findCertRecordsInList(filter, attrs, CertRecord.ATTR_ID, + pageSize); + } + + public ICertRecordList findCertRecordsInList(String filter, + String attrs[], String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + CMS.debug("In findCertRecordsInList"); + CertRecordList list = null; + + try { + IDBVirtualList<ICertRecord> vlist = s.<ICertRecord>createVirtualList(getDN(), filter, attrs, + sortKey, pageSize); + + list = new CertRecordList(vlist); + } finally { + if (s != null) + s.close(); + } + return list; + } + + public ICertRecordList findCertRecordsInList(String filter, + String attrs[], String jumpTo, String sortKey, int pageSize) + throws EBaseException { + return findCertRecordsInList(filter, attrs, jumpTo, false, sortKey, pageSize); + + } + + public ICertRecordList findCertRecordsInList(String filter, + String attrs[], String jumpTo, boolean hardJumpTo, + String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + CertRecordList list = null; + + CMS.debug("In findCertRecordsInList with Jumpto " + jumpTo); + try { + String jumpToVal = null; + + if (hardJumpTo) { + CMS.debug("In findCertRecordsInList with hardJumpto "); + jumpToVal = "99"; + } else { + int len = jumpTo.length(); + + if (len > 9) { + jumpToVal = Integer.toString(len) + jumpTo; + } else { + jumpToVal = "0" + Integer.toString(len) + jumpTo; + } + } + + IDBVirtualList<ICertRecord> vlist = s.createVirtualList(getDN(), filter, + attrs, jumpToVal, sortKey, pageSize); + + list = new CertRecordList(vlist); + } finally { + if (s != null) + s.close(); + } + return list; + } + + public ICertRecordList findCertRecordsInListRawJumpto(String filter, + String attrs[], String jumpTo, String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + CertRecordList list = null; + + CMS.debug("In findCertRecordsInListRawJumpto with Jumpto " + jumpTo); + + try { + + IDBVirtualList<ICertRecord> vlist = s.createVirtualList(getDN(), filter, + attrs, jumpTo, sortKey, pageSize); + + list = new CertRecordList(vlist); + } finally { + if (s != null) + s.close(); + } + return list; + } + + /** + * Marks certificate as renewable. + */ + public void markCertificateAsRenewable(ICertRecord record) + throws EBaseException { + changeRenewalAttribute(((CertRecord) record).getSerialNumber().toString(), + CertRecord.AUTO_RENEWAL_ENABLED); + } + + /** + * Marks certificate as renewable. + */ + public void markCertificateAsNotRenewable(ICertRecord record) + throws EBaseException { + changeRenewalAttribute(((CertRecord) record).getSerialNumber().toString(), + CertRecord.AUTO_RENEWAL_DISABLED); + } + + public void markCertificateAsRenewed(String serialNo) + throws EBaseException { + changeRenewalAttribute(serialNo, CertRecord.AUTO_RENEWAL_DONE); + } + + public void markCertificateAsRenewalNotified(String serialNo) + throws EBaseException { + changeRenewalAttribute(serialNo, CertRecord.AUTO_RENEWAL_NOTIFIED); + } + + private void changeRenewalAttribute(String serialno, String value) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + serialno + + "," + getDN(); + ModificationSet mods = new ModificationSet(); + + mods.add(CertRecord.ATTR_AUTO_RENEW, Modification.MOD_REPLACE, + value); + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + /** + * temp solution... + */ + public class RenewableCertificateCollection { + Vector<Object> mToRenew = null; + Vector<Object> mToNotify = null; + + public RenewableCertificateCollection() { + } + + public Vector<Object> getRenewable() { + return mToRenew; + } + + public Vector<Object> getNotifiable() { + return mToNotify; + } + + public void addCertificate(String renewalFlag, Object o) { + if (renewalFlag.equals(CertRecord.AUTO_RENEWAL_ENABLED)) { + if (mToRenew == null) + mToRenew = new Vector<Object>(); + mToRenew.addElement(o); + } + if (renewalFlag.equals(CertRecord.AUTO_RENEWAL_DISABLED)) { + if (mToNotify == null) + mToNotify = new Vector<Object>(); + mToNotify.addElement(o); + } + } + } + + public Hashtable<String, RenewableCertificateCollection> getRenewableCertificates(String renewalTime) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + Hashtable<String, RenewableCertificateCollection> tab = null; + + try { + String filter = "(&(" + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_VALID + ")(" + + CertRecord.ATTR_X509CERT + + "." + CertificateValidity.NOT_AFTER + "<=" + renewalTime + + ")(!(" + CertRecord.ATTR_AUTO_RENEW + "=" + + CertRecord.AUTO_RENEWAL_DONE + + "))(!(" + CertRecord.ATTR_AUTO_RENEW + "=" + + CertRecord.AUTO_RENEWAL_NOTIFIED + ")))"; + //Enumeration e = s.search(getDN(), filter); + ICertRecordList list = null; + + list = findCertRecordsInList(filter, null, "serialno", 10); + int size = list.getSize(); + Enumeration<ICertRecord> e = list.getCertRecords(0, size - 1); + + tab = new Hashtable<String, RenewableCertificateCollection>(); + while (e.hasMoreElements()) { + CertRecord rec = (CertRecord) e.nextElement(); + X509CertImpl cert = rec.getCertificate(); + String subjectDN = cert.getSubjectDN().toString(); + String renewalFlag = rec.getAutoRenew(); + + // See if the subjectDN is in the table + Object val = null; + + if ((val = tab.get(subjectDN)) == null) { + RenewableCertificateCollection collection = + new RenewableCertificateCollection(); + + collection.addCertificate(renewalFlag, cert); + tab.put(subjectDN, collection); + } else { + ((RenewableCertificateCollection) val).addCertificate(renewalFlag, cert); + } + } + } finally { + if (s != null) + s.close(); + } + return tab; + } + + /** + * Gets all valid and unexpired certificates pertaining + * to a subject DN. + * + * @param subjectDN The distinguished name of the subject. + * @param validityType The type of certificates to get. + * @return An array of certificates. + */ + + public X509CertImpl[] getX509Certificates(String subjectDN, + int validityType) throws EBaseException { + IDBSSession s = mDBService.createSession(); + + X509CertImpl certs[] = null; + + try { + // XXX - not checking validityType... + String filter = "(&(" + CertRecord.ATTR_X509CERT + + "." + X509CertInfo.SUBJECT + "=" + subjectDN; + + if (validityType == ALL_VALID_CERTS) { + filter += ")(" + + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_VALID; + } + if (validityType == ALL_UNREVOKED_CERTS) { + filter += ")(|(" + + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_VALID + ")(" + + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_EXPIRED + ")"; + } + filter += "))"; + + //Enumeration e = s.search(getDN(), filter); + ICertRecordList list = null; + + list = findCertRecordsInList(filter, null, "serialno", 10); + int size = list.getSize(); + Enumeration<ICertRecord> e = list.getCertRecords(0, size - 1); + + Vector<X509CertImpl> v = new Vector<X509CertImpl>(); + + while (e.hasMoreElements()) { + CertRecord rec = (CertRecord) e.nextElement(); + + v.addElement(rec.getCertificate()); + } + if (v.size() == 0) + return null; + certs = new X509CertImpl[v.size()]; + v.copyInto(certs); + } finally { + if (s != null) + s.close(); + } + return certs; + } + + public X509CertImpl[] getX509Certificates(String filter) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + X509CertImpl certs[] = null; + + try { + Enumeration<ICertRecord> e = null; + + if (filter != null && filter.length() > 0) { + //e = s.search(getDN(), filter); + ICertRecordList list = null; + + list = findCertRecordsInList(filter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } + + Vector<X509CertImpl> v = new Vector<X509CertImpl>(); + + while (e != null && e.hasMoreElements()) { + CertRecord rec = (CertRecord) e.nextElement(); + + v.addElement(rec.getCertificate()); + } + if (v.size() > 0) { + certs = new X509CertImpl[v.size()]; + v.copyInto(certs); + } + } finally { + if (s != null) + s.close(); + } + return certs; + } + + /** + * Retrives all valid certificates excluding ones already revoked. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getValidCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<ICertRecord> v = new Vector<ICertRecord>(); + + try { + + // 'from' determines 'jumpto' value + // 'to' determines where to stop looking + + String ldapfilter = "(certstatus=VALID)"; + + String fromVal = "0"; + try { + if (from != null) { + Integer.parseInt(from); + fromVal = from; + } + } catch (Exception e1) { + // from is not integer + } + + ICertRecordList list = + findCertRecordsInList(ldapfilter, null, fromVal, "serialno", 40); + + BigInteger toInt = null; + if (to != null && !to.trim().equals("")) { + toInt = new BigInteger(to); + } + + for (int i = 0;; i++) { + CertRecord rec = (CertRecord) list.getCertRecord(i); + CMS.debug("processing record: " + i); + if (rec == null) { + break; // no element returned + } else { + + CMS.debug("processing record: " + i + " " + rec.getSerialNumber()); + // Check if we are past the 'to' marker + if (toInt != null) { + if (rec.getSerialNumber().compareTo(toInt) > 0) { + break; + } + } + v.addElement(rec); + } + } + + } finally { + if (s != null) + s.close(); + } + CMS.debug("returning " + v.size() + " elements"); + return v.elements(); + } + + /** + * Retrives all valid certificates excluding ones already revoked. + */ + public Enumeration<ICertRecord> getAllValidCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&(!(" + CertRecord.ATTR_REVO_INFO + "=*))(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_BEFORE + "<=" + + DateMapper.dateToDB(now) + ")(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + "))"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all valid not published certificates + * excluding ones already revoked. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getValidNotPublishedCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&("; + + if (from != null && from.length() > 0) + ldapfilter += CertRecord.ATTR_ID + ">=" + from + ")("; + if (to != null && to.length() > 0) + ldapfilter += CertRecord.ATTR_ID + "<=" + to + ")("; + ldapfilter += "!(" + CertRecord.ATTR_REVO_INFO + "=*))(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_BEFORE + "<=" + + DateMapper.dateToDB(now) + ")(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + ")(!(" + + "certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true)))"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + + } finally { + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all valid not published certificates + * excluding ones already revoked. + */ + public Enumeration<ICertRecord> getAllValidNotPublishedCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&(!(" + CertRecord.ATTR_REVO_INFO + "=*))(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_BEFORE + "<=" + + DateMapper.dateToDB(now) + ")(" + + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + ")(!(" + + "certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true)))"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all expired certificates. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getExpiredCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&("; + + if (from != null && from.length() > 0) + ldapfilter += CertRecord.ATTR_ID + ">=" + from + ")("; + if (to != null && to.length() > 0) + ldapfilter += CertRecord.ATTR_ID + "<=" + to + ")("; + ldapfilter += "!(" + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + ")))"; + //e = s.search(getDN(), ldapfilter); + + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all expired certificates. + */ + public Enumeration<ICertRecord> getAllExpiredCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(!(" + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + "))"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all expired published certificates. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getExpiredPublishedCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&("; + + if (from != null && from.length() > 0) + ldapfilter += CertRecord.ATTR_ID + ">=" + from + ")("; + if (to != null && to.length() > 0) + ldapfilter += CertRecord.ATTR_ID + "<=" + to + ")("; + ldapfilter += "!(" + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + //DateMapper.dateToDB(now) + ")))"; + DateMapper.dateToDB(now) + "))(" + + "certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true))"; + //e = s.search(getDN(), ldapfilter); + + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all expired publishedcertificates. + */ + public Enumeration<ICertRecord> getAllExpiredPublishedCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + Date now = CMS.getCurrentDate(); + String ldapfilter = "(&"; + + ldapfilter += "(!(" + CertRecord.ATTR_X509CERT + "." + + CertificateValidity.NOT_AFTER + ">=" + + DateMapper.dateToDB(now) + "))"; + ldapfilter += "(certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true))"; + + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + public ICertRecordList getInvalidCertsByNotBeforeDate(Date date, int pageSize) + throws EBaseException { + + ICertRecordList list = null; + IDBSSession s = mDBService.createSession(); + + try { + String ldapfilter = "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_INVALID + ")"; + + String[] attrs = null; + + if (mConsistencyCheck == false) { + attrs = new String[] { "objectclass", CertRecord.ATTR_ID, CertRecord.ATTR_X509CERT }; + } + + CMS.debug("getInvalidCertificatesByNotBeforeDate filter " + ldapfilter); + //e = s.search(getDN(), ldapfilter); + CMS.debug("getInvalidCertificatesByNotBeforeDate: about to call findCertRecordsInList"); + + list = findCertRecordsInListRawJumpto(ldapfilter, attrs, + DateMapper.dateToDB(date), "notBefore", pageSize); + + //e = list.getCertRecords(0, size - 1); + + } finally { + // XXX - transaction is not done at this moment + + CMS.debug("In getInvalidCertsByNotBeforeDate finally."); + + if (s != null) + s.close(); + } + return list; + + } + + public ICertRecordList getValidCertsByNotAfterDate(Date date, int pageSize) + throws EBaseException { + + ICertRecordList list = null; + IDBSSession s = mDBService.createSession(); + + try { + String ldapfilter = "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_VALID + ")"; + + String[] attrs = null; + + if (mConsistencyCheck == false) { + attrs = new String[] { "objectclass", CertRecord.ATTR_ID, CertRecord.ATTR_X509CERT }; + } + + CMS.debug("getValidCertsByNotAfterDate filter " + ldapfilter); + //e = s.search(getDN(), ldapfilter); + list = findCertRecordsInListRawJumpto(ldapfilter, attrs, DateMapper.dateToDB(date), "notAfter", pageSize); + + } finally { + // XXX - transaction is not done at this moment + + if (s != null) + s.close(); + } + return list; + } + + public ICertRecordList getRevokedCertsByNotAfterDate(Date date, int pageSize) + throws EBaseException { + + ICertRecordList list = null; + IDBSSession s = mDBService.createSession(); + + try { + String ldapfilter = "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED + ")"; + + String[] attrs = null; + + if (mConsistencyCheck == false) { + attrs = new String[] { "objectclass", CertRecord.ATTR_REVOKED_ON, CertRecord.ATTR_ID, + CertRecord.ATTR_REVO_INFO, CertificateValidity.NOT_AFTER, CertRecord.ATTR_X509CERT }; + } + + CMS.debug("getRevokedCertificatesByNotAfterDate filter " + ldapfilter); + //e = s.search(getDN(), ldapfilter); + CMS.debug("getRevokedCertificatesByNotAfterDate: about to call findCertRecordsInList"); + + list = findCertRecordsInListRawJumpto(ldapfilter, attrs, + DateMapper.dateToDB(date), "notafter", pageSize); + + } finally { + // XXX - transaction is not done at this moment + + if (s != null) + s.close(); + } + return list; + + } + + /** + * Retrieves all revoked certificates in the serial number range. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getRevokedCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + String ldapfilter = "(&(" + CertRecord.ATTR_REVO_INFO + "=*)"; + + if (from != null && from.length() > 0) + ldapfilter += "(" + CertRecord.ATTR_ID + ">=" + from + ")"; + if (to != null && to.length() > 0) + ldapfilter += "(" + CertRecord.ATTR_ID + "<=" + to + ")"; + ldapfilter += ")"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all revoked certificates including ones already expired or + * not yet valid. + */ + public Enumeration<ICertRecord> getAllRevokedCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + // index is setup for this filter + String ldapfilter = "(|(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED + ")(" + + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED_EXPIRED + "))"; + + try { + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrieves all revoked publishedcertificates in the serial number range. + * + * @param from The starting point of the serial number range. + * @param to The ending point of the serial number range. + */ + public Enumeration<ICertRecord> getRevokedPublishedCertificates(String from, String to) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + String ldapfilter = "(&(" + CertRecord.ATTR_REVO_INFO + "=*)"; + + if (from != null && from.length() > 0) + ldapfilter += "(" + CertRecord.ATTR_ID + ">=" + from + ")"; + if (to != null && to.length() > 0) + ldapfilter += "(" + CertRecord.ATTR_ID + "<=" + to + ")"; + //ldapfilter += ")"; + ldapfilter += "(certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true))"; + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all revoked published certificates including ones + * already expired or not yet valid. + */ + public Enumeration<ICertRecord> getAllRevokedPublishedCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + // index is setup for this filter + String ldapfilter = "(&(|(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED + ")(" + + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED_EXPIRED + "))"; + + ldapfilter += "(certMetainfo=" + + CertRecord.META_LDAPPUBLISH + + ":true))"; + try { + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrieves all revoked certificates that have not expired. + */ + public Enumeration<ICertRecord> getRevokedCertificates(Date asOfDate) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + + try { + + /*e = s.search(getDN(), "(&(" + + CertRecord.ATTR_REVO_INFO + "=*)(" + CertRecord.ATTR_X509CERT + + "." + CertificateValidity.NOT_AFTER + " >= " + + DateMapper.dateToDB(asOfDate) + "))");*/ + String ldapfilter = "(&(" + + CertRecord.ATTR_REVO_INFO + "=*)(" + CertRecord.ATTR_X509CERT + + "." + CertificateValidity.NOT_AFTER + " >= " + + DateMapper.dateToDB(asOfDate) + "))"; + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + // XXX - transaction is not done at this moment + if (s != null) + s.close(); + } + return e; + } + + /** + * Retrives all revoked certificates excluing ones already expired. + */ + public Enumeration<ICertRecord> getAllRevokedNonExpiredCertificates() + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Enumeration<ICertRecord> e = null; + String ldapfilter = "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED + ")"; // index is setup for this filter + + try { + //e = s.search(getDN(), ldapfilter); + ICertRecordList list = null; + + list = findCertRecordsInList(ldapfilter, null, "serialno", 10); + int size = list.getSize(); + + e = list.getCertRecords(0, size - 1); + } finally { + if (s != null) + s.close(); + } + return e; + } + + LDAPSearchResults searchForModifiedCertificateRecords(IDBSSession session) { + CMS.debug("searchForModifiedCertificateRecords"); + LDAPSearchResults results = null; + + String filter = "(" + CertRecord.ATTR_CERT_STATUS + "=*)"; + try { + results = session.persistentSearch(getDN(), filter, null); + + } catch (Exception e) { + CMS.debug("startSearchForModifiedCertificateRecords persistentSearch Exception=" + e); + } + + return results; + } + + public void getModifications(LDAPEntry entry) { + if (entry != null) { + CMS.debug("getModifications entry DN=" + entry.getDN()); + + LDAPAttributeSet entryAttrs = entry.getAttributeSet(); + ICertRecord certRec = null; + try { + certRec = (ICertRecord) mDBService.getRegistry().createObject(entryAttrs); + } catch (Exception e) { + } + if (certRec != null) { + String status = certRec.getStatus(); + CMS.debug("getModifications serialNumber=" + certRec.getSerialNumber() + + " status=" + status); + if (status != null && (status.equals(ICertRecord.STATUS_VALID) || + status.equals(ICertRecord.STATUS_REVOKED))) { + + Enumeration<ICRLIssuingPoint> eIPs = mCRLIssuingPoints.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = eIPs.nextElement(); + + if (ip != null) { + if (status.equals(ICertRecord.STATUS_REVOKED)) { + IRevocationInfo rInfo = certRec.getRevocationInfo(); + if (rInfo != null) { + ip.addRevokedCert(certRec.getSerialNumber(), + new RevokedCertImpl(certRec.getSerialNumber(), + rInfo.getRevocationDate(), + rInfo.getCRLEntryExtensions())); + } + } else { + ip.addUnrevokedCert(certRec.getSerialNumber()); + } + } + } + + } + } + } else { + CMS.debug("getModifications entry == null"); + } + } + + /** + * Checks if the presented certificate belongs to the repository + * and is revoked. + * + * @param cert certificate to verify. + * @return RevocationInfo if the presented certificate is revoked otherwise null. + */ + public RevocationInfo isCertificateRevoked(X509CertImpl cert) + throws EBaseException { + RevocationInfo info = null; + + // 615932 + if (cert == null) + return null; + + ICertRecord rec = readCertificateRecord(cert.getSerialNumber()); + + if (rec != null) { + if (rec.getStatus().equals(ICertRecord.STATUS_REVOKED)) { + X500Name name = (X500Name) cert.getSubjectDN(); + X500Name repCertName = (X500Name) rec.getCertificate().getSubjectDN(); + + if (name.equals(repCertName)) { + byte[] certEncoded = null; + byte[] repCertEncoded = null; + + try { + certEncoded = cert.getEncoded(); + repCertEncoded = rec.getCertificate().getEncoded(); + } catch (Exception e) { + } + + if (certEncoded != null && + repCertEncoded != null && + certEncoded.length == repCertEncoded.length) { + int i; + + for (i = 0; i < certEncoded.length; i++) { + if (certEncoded[i] != repCertEncoded[i]) + break; + } + if (i >= certEncoded.length) { + info = (RevocationInfo) ((CertRecord) rec).getRevocationInfo(); + } + } + } + } + } + + return info; + } + + public void shutdown() { + if (certStatusUpdateTask != null) { + certStatusUpdateTask.stop(); + } + + if (retrieveModificationsTask != null) { + retrieveModificationsTask.stop(); + } + } +} + +class CertStatusUpdateTask implements Runnable { + + CertificateRepository repository; + int interval; + + ScheduledExecutorService executorService; + + public CertStatusUpdateTask(CertificateRepository repository, int interval) { + this.repository = repository; + this.interval = interval; + } + + public void start() { + // schedule task to run immediately and repeat after specified interval + executorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + public Thread newThread(Runnable r) { + return new Thread(r, "CertStatusUpdateTask"); + } + }); + executorService.scheduleWithFixedDelay(this, 0, interval, TimeUnit.SECONDS); + } + + public void run() { + repository.updateCertStatus(); + } + + public void stop() { + // shutdown executorService without interrupting running task + if (executorService != null) executorService.shutdown(); + } +} + +class RetrieveModificationsTask implements Runnable { + + CertificateRepository repository; + + IDBSSession session; + LDAPSearchResults results; + + ScheduledExecutorService executorService; + + public RetrieveModificationsTask(CertificateRepository repository) { + this.repository = repository; + } + + public void start() throws EBaseException { + // start persistent search + try { + session = repository.getDBSubsystem().createSession(); + results = repository.searchForModifiedCertificateRecords(session); + } catch (EBaseException e) { + stop(); // avoid leaks + throw e; + } + + // schedule task to run immediately and repeat without delay + executorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() { + public Thread newThread(Runnable r) { + return new Thread(r, "RetrieveModificationsTask"); + } + }); + executorService.scheduleWithFixedDelay(this, 0, 1, TimeUnit.MICROSECONDS); + } + + public void run() { + CMS.debug("Inside run method of RetrieveModificationsThread"); + + try { + // results.hasMoreElements() will block until next element becomes available + // or return false if the search is abandoned or connection is closed + if (results.hasMoreElements()) { + LDAPEntry entry = results.next(); + repository.getModifications(entry); + } + } catch (Exception e) { + CMS.debug("Exception: " + e.toString()); + } + CMS.debug("Done with run method of RetrieveModificationsThread"); + } + + public void stop() { + if (executorService != null) executorService.shutdown(); + + if (session != null) { + // closing the session doesn't actually close the connection, + // so the search needs to be abandoned explicitly + if (results != null) try { session.abandon(results); } catch (Exception e) { e.printStackTrace(); } + + // close session + try { session.close(); } catch (Exception e) { e.printStackTrace(); } + } + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBRegistry.java b/base/common/src/com/netscape/cmscore/dbs/DBRegistry.java new file mode 100644 index 000000000..20e40a8e3 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBRegistry.java @@ -0,0 +1,564 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBDynAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IFilterConverter; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents a registry where all the + * schema (object classes and attribute) information + * is stored. + * + * Attribute mappers can be registered with this + * registry. + * + * Given the schema information stored, this registry + * has knowledge to convert a Java object into a + * LDAPAttributeSet or vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DBRegistry implements IDBRegistry, ISubsystem { + + private IConfigStore mConfig = null; + private Hashtable<String, String[]> mOCclassNames = new Hashtable<String, String[]>(); + private Hashtable<String, NameAndObject> mOCldapNames = new Hashtable<String, NameAndObject>(); + private Hashtable<String, IDBAttrMapper> mAttrufNames = new Hashtable<String, IDBAttrMapper>(); + private IFilterConverter mConverter = null; + private Vector<IDBDynAttrMapper> mDynAttrMappers = new Vector<IDBDynAttrMapper>(); + + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs registry. + */ + public DBRegistry() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return "dbsregistry"; + } + + /** + * Sets subsystem identifier. This is an internal + * subsystem, and is not loadable. + */ + public void setId(String id) throws EBaseException { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")); + } + + /** + * Initializes the internal registery. Connects to the + * data source, and create a pool of connection of which + * applications can use. Optionally, check the integrity + * of the database. + */ + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mConfig = config; + mConverter = new LdapFilterConverter(mAttrufNames); + } + + /** + * Retrieves configuration store. + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Starts up this subsystem. + */ + public void startup() throws EBaseException { + } + + /** + * Shutdowns this subsystem gracefully. + */ + public void shutdown() { + mOCclassNames.clear(); + mOCclassNames = null; + mOCldapNames.clear(); + mOCldapNames = null; + mAttrufNames.clear(); + mAttrufNames = null; + mConverter = null; + } + + /** + * Registers object class. + */ + public void registerObjectClass(String className, String ldapNames[]) + throws EDBException { + try { + Class<?> c = Class.forName(className); + + mOCclassNames.put(className, ldapNames); + mOCldapNames.put(sortAndConcate( + ldapNames).toLowerCase(), + new NameAndObject(className, c)); + } catch (ClassNotFoundException e) { + + /*LogDoc + * + * @phase db startup + * @reason failed to register object class + * @message DBRegistry: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_INVALID_CLASS_NAME", className)); + } + } + + /** + * See if an object class is registered. + */ + public boolean isObjectClassRegistered(String className) { + return mOCclassNames.containsKey(className); + } + + /** + * Registers attribute mapper. + */ + public void registerAttribute(String ufName, IDBAttrMapper mapper) + throws EDBException { + // should not allows 'objectclass' as attribute; it has + // special meaning + mAttrufNames.put(ufName.toLowerCase(), mapper); + } + + /** + * See if an attribute is registered. + */ + public boolean isAttributeRegistered(String ufName) { + return mAttrufNames.containsKey(ufName.toLowerCase()); + } + + public void registerDynamicMapper(IDBDynAttrMapper mapper) { + mDynAttrMappers.add(mapper); + } + + /** + * Creates LDAP-based search filters with help of + * registered mappers. + * Parses filter from filter string specified in RFC1558. + * + * <pre> + * <filter> ::= '(' <filtercomp> ')' + * <filtercomp> ::= <and> | <or> | <not> | <item> + * <and> ::= '&' <filterlist> + * <or> ::= '|' <filterlist> + * <not> ::= '!' <filter> + * <filterlist> ::= <filter> | <filter> <filterlist> + * <item> ::= <simple> | <present> | <substring> + * <simple> ::= <attr> <filtertype> <value> + * <filtertype> ::= <equal> | <approx> | <greater> | <less> + * <equal> ::= '=' + * <approx> ::= '~=' + * <greater> ::= '>=' + * <less> ::= '<=' + * <present> ::= <attr> '=*' + * <substring> ::= <attr> '=' <initial> <any> <final> + * <initial> ::= NULL | <value> + * <any> ::= '*' <starval> + * <starval> ::= NULL | <value> '*' <starval> + * <final> ::= NULL | <value> + * </pre> + */ + public String getFilter(String filter) throws EBaseException { + return getFilter(filter, mConverter); + } + + public String getFilter(String filter, IFilterConverter c) + throws EBaseException { + String f = filter; + + f = f.trim(); + if (f.startsWith("(") && f.endsWith(")")) { + return "(" + getFilterComp(f.substring(1, + f.length() - 1), c) + ")"; + } else { + return getFilterComp(filter, c); + } + } + + private String getFilterComp(String f, IFilterConverter c) + throws EBaseException { + f = f.trim(); + if (f.startsWith("&")) { // AND operation + return "&" + getFilterList(f.substring(1, + f.length()), c); + } else if (f.startsWith("|")) { // OR operation + return "|" + getFilterList(f.substring(1, + f.length()), c); + } else if (f.startsWith("!")) { // NOT operation + return "!" + getFilter(f.substring(1, f.length()), c); + } else { // item + return getFilterItem(f, c); + } + } + + private String getFilterList(String f, IFilterConverter c) + throws EBaseException { + f = f.trim(); + int level = 0; + int start = 0; + int end = 0; + Vector<String> v = new Vector<String>(); + + for (int i = 0; i < f.length(); i++) { + if (f.charAt(i) == '(') { + if (level == 0) { + start = i; + } + level++; + } + if (f.charAt(i) == ')') { + level--; + if (level == 0) { + end = i; + String filter = getFilter(f.substring(start, end + 1), c); + + v.addElement(filter); + } + } + } + String result = ""; + + for (int i = 0; i < v.size(); i++) { + result += (String) v.elementAt(i); + } + return result; + } + + /** + * So, here we need to separate item into name, op, value. + */ + private String getFilterItem(String f, IFilterConverter c) + throws EBaseException { + f = f.trim(); + int idx = f.indexOf('='); + + if (idx == -1) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_INVALID_FILTER_ITEM", "=")); + } + + String type = f.substring(0, idx).trim(); + String value = f.substring(idx + 1).trim(); // skip '=' + + // make decision by looking at the type + type = type.trim(); + if (type.endsWith("~")) { + // approximate match + String name = type.substring(0, type.length() - 1).trim(); + + return c.convert(name, "~=", value); + } else if (type.endsWith("!")) { + String name = type.substring(0, type.length() - 1).trim(); + + return c.convert(name, "!=", value); + } else if (type.endsWith(">")) { + // greater than + String name = type.substring(0, type.length() - 1).trim(); + + return c.convert(name, ">=", value); + } else if (type.endsWith("<")) { + String name = type.substring(0, type.length() - 1).trim(); + + return c.convert(name, "<=", value); + } + + // for those that are not simple + if (value.startsWith("*") && value.length() == 1) { + return c.convert(type, "=", "*"); + } + + // if value contains no '*', then it is equality + if (value.indexOf('*') == -1) { + if (type.equals("objectclass")) { + String ldapNames[] = (String[]) + mOCclassNames.get(value); + + if (ldapNames == null) + throw new EDBException( + CMS.getUserMessage("CMS_DBS_INVALID_FILTER_ITEM", f)); + String filter = ""; + + for (int g = 0; g < ldapNames.length; g++) { + filter += "(objectclass=" + + ldapNames[g] + ")"; + } + return "&" + filter; + } else { + return c.convert(type, "=", value); + } + } + // XXX - does not support substring!! + return c.convert(type, "=", value); + } + + /** + * Maps object into LDAP attribute set. + */ + public void mapObject(IDBObj parent, String name, Object obj, + LDAPAttributeSet attrs) throws EBaseException { + IDBAttrMapper mapper = (IDBAttrMapper) mAttrufNames.get( + name.toLowerCase()); + + if (mapper == null) { + return; // no mapper found, just skip this attribute + } + mapper.mapObjectToLDAPAttributeSet(parent, name, obj, attrs); + } + + /** + * Retrieves a list of LDAP attributes that are associated + * with the given attributes. + * This method is used for searches, to map the database attributes + * to LDAP attributes. + */ + public String[] getLDAPAttributes(String attrs[]) + throws EBaseException { + IDBAttrMapper mapper; + + if (attrs == null) + return null; + Vector<String> v = new Vector<String>(); + + for (int i = 0; i < attrs.length; i++) { + + if (attrs[i].equals("objectclass")) { + v.addElement("objectclass"); + continue; + } + + if (isAttributeRegistered(attrs[i])) { + mapper = (IDBAttrMapper) + mAttrufNames.get(attrs[i].toLowerCase()); + if (mapper == null) { + throw new EDBException(CMS.getUserMessage("CMS_DBS_INVALID_ATTRS")); + } + Enumeration<String> e = mapper.getSupportedLDAPAttributeNames(); + + while (e.hasMoreElements()) { + String s = (String) e.nextElement(); + + if (!v.contains(s)) { + v.addElement(s); + } + } + } else { + IDBDynAttrMapper matchingDynAttrMapper = null; + // check if a dynamic mapper can handle the attribute + for (Iterator<IDBDynAttrMapper> dynMapperIter = mDynAttrMappers.iterator(); dynMapperIter.hasNext();) { + IDBDynAttrMapper dynAttrMapper = + (IDBDynAttrMapper) dynMapperIter.next(); + if (dynAttrMapper.supportsLDAPAttributeName(attrs[i])) { + matchingDynAttrMapper = dynAttrMapper; + break; + } + } + if (matchingDynAttrMapper != null) { + v.addElement(attrs[i]); + } else { + /*LogDoc + * + * @phase retrieve ldap attr + * @reason failed to get registered object class + * @message DBRegistry: <attr> is not registered + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_DBS_ATTR_NOT_REGISTER", attrs[i])); + throw new EDBException(CMS.getLogMessage("CMSCORE_DBS_ATTR_NOT_REGISTER", attrs[i])); + } + } + + } + if (v.size() == 0) + return null; + String ldapAttrs[] = new String[v.size()]; + + v.copyInto(ldapAttrs); + return ldapAttrs; + } + + /** + * Creates attribute set from object. + */ + public LDAPAttributeSet createLDAPAttributeSet(IDBObj obj) + throws EBaseException { + Enumeration<String> e = obj.getSerializableAttrNames(); + LDAPAttributeSet attrs = new LDAPAttributeSet(); + + // add object class to attribute set + String className = ((Object) obj).getClass().getName(); + String vals[] = (String[]) mOCclassNames.get(className); + + attrs.add(new LDAPAttribute("objectclass", vals)); + + // give every attribute a chance to put stuff in attr set + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + + if (obj.get(name) != null) { + mapObject(obj, name, obj.get(name), attrs); + } + } + return attrs; + } + + /** + * Creates object from attribute set. + */ + public IDBObj createObject(LDAPAttributeSet attrs) + throws EBaseException { + // map object class attribute to object + LDAPAttribute attr = attrs.getAttribute("objectclass"); + + //CMS.debug("createObject: attrs " + attrs.toString()); + + attrs.remove("objectclass"); + + // sort the object class values + @SuppressWarnings("unchecked") + Enumeration<String> vals = attr.getStringValues(); + Vector<String> v = new Vector<String>(); + + while (vals.hasMoreElements()) { + v.addElement(vals.nextElement()); + } + String s[] = new String[v.size()]; + + v.copyInto(s); + String sorted = sortAndConcate(s).toLowerCase(); + NameAndObject no = (NameAndObject) mOCldapNames.get(sorted); + + if (no == null) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_INVALID_CLASS_NAME", sorted)); + } + Class<?> c = (Class<?>) no.getObject(); + + try { + IDBObj obj = (IDBObj) c.newInstance(); + Enumeration<String> ee = obj.getSerializableAttrNames(); + + while (ee.hasMoreElements()) { + String oname = (String) ee.nextElement(); + IDBAttrMapper mapper = (IDBAttrMapper) + mAttrufNames.get( + oname.toLowerCase()); + + if (mapper == null) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_NO_MAPPER_FOUND", oname)); + } + mapper.mapLDAPAttributeSetToObject(attrs, + oname, obj); + } + return obj; + } catch (Exception e) { + + /*LogDoc + * + * @phase create ldap attr + * @reason failed to create object class + * @message DBRegistry: <attr> is not registered + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + throw new EDBException(CMS.getUserMessage("CMS_DBS_INVALID_ATTRS")); + } + } + + /** + * Sorts and concate given strings. + */ + private String sortAndConcate(String s[]) { + Vector<String> v = new Vector<String>(); + + // sort it first + for (int i = 0; i < s.length; i++) { + for (int j = 0; j < v.size(); j++) { + String t = (String) v.elementAt(j); + + if (s[i].compareTo(t) < 0) { + v.insertElementAt(s[i], j); + break; + } + } + if (i != (v.size() - 1)) + v.addElement(s[i]); + } + + // concate them + String result = ""; + + for (int i = 0; i < v.size(); i++) { + result += ((String) v.elementAt(i) + "+"); + } + return result; + } +} + +/** + * Just a convenient container class. + */ +class NameAndObject { + + private String mN = null; + private Object mO = null; + + public NameAndObject(String name, Object o) { + mN = name; + mO = o; + } + + public String getName() { + return mN; + } + + public Object getObject() { + return mO; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBSSession.java b/base/common/src/com/netscape/cmscore/dbs/DBSSession.java new file mode 100644 index 000000000..ddc9f1874 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBSSession.java @@ -0,0 +1,485 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPModification; +import netscape.ldap.LDAPModificationSet; +import netscape.ldap.LDAPSearchConstraints; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPv2; +import netscape.ldap.controls.LDAPPersistSearchControl; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.EDBNotAvailException; +import com.netscape.certsrv.dbs.EDBRecordNotFoundException; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents the database session. Operations + * can be performed with a session. + * + * Transaction and Caching support can be integrated + * into session. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DBSSession implements IDBSSession { + + private IDBSubsystem mDBSystem = null; + private LDAPConnection mConn = null; + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs a database session. + * + * @param system the database subsytem + * @param c the ldap connection + */ + public DBSSession(IDBSubsystem system, LDAPConnection c) { + mDBSystem = system; + mConn = c; + try { + // no limit + mConn.setOption(LDAPv2.SIZELIMIT, Integer.valueOf(0)); + } catch (LDAPException e) { + } + } + + /** + * Returns database subsystem. + */ + public ISubsystem getDBSubsystem() { + return mDBSystem; + } + + /** + * Closes this session. + */ + public void close() throws EDBException { + // return ldap connection. + mDBSystem.returnConn(mConn); + } + + /** + * Adds object to backend database. For example, + * + * <PRE> + * session.add("cn=123459,o=certificate repository,o=airius.com", + * certRec); + * </PRE> + * + * @param name the name of the ldap entry + * @param obj the DBobj that can be mapped to ldap attrubute set + */ + public void add(String name, IDBObj obj) throws EBaseException { + try { + LDAPAttributeSet attrs = mDBSystem.getRegistry( + ).createLDAPAttributeSet(obj); + LDAPEntry e = new LDAPEntry(name, attrs); + + /*LogDoc + * + * @phase local ldap add + * @message DBSSession: begin LDAP add <entry> + */ + mConn.add(e); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + name + " " + e.toString())); + } + } + + /** + * Reads an object from the database. + * all attributes will be returned + * + * @param name the name of the ldap entry + */ + public IDBObj read(String name) throws EBaseException { + return read(name, null); + } + + /** + * Reads an object from the database, and only populates + * the selected attributes. + * + * @param name the name of the ldap entry + * @param attrs the attributes to be selected + */ + public IDBObj read(String name, String attrs[]) + throws EBaseException { + try { + String ldapattrs[] = null; + + if (attrs != null) { + ldapattrs = mDBSystem.getRegistry( + ).getLDAPAttributes(attrs); + } + + /*LogDoc + * + * @phase local ldap read + * @message DBSSession: begin LDAP read <entry> + */ + LDAPSearchResults res = mConn.search(name, + LDAPv2.SCOPE_BASE, "(objectclass=*)", + ldapattrs, false); + LDAPEntry entry = (LDAPEntry) res.nextElement(); + + return mDBSystem.getRegistry().createObject( + entry.getAttributeSet()); + } catch (LDAPException e) { + + /*LogDoc + * + * @phase local ldap read + * @message DBSSession: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_INFO, "DBSSession: " + e.toString()); + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) + throw new EDBRecordNotFoundException( + CMS.getUserMessage("CMS_DBS_RECORD_NOT_FOUND")); + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + name + " " + e.toString())); + } + } + + /** + * Deletes object from database. + */ + public void delete(String name) throws EBaseException { + try { + mConn.delete(name); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + name + " " + e.toString())); + } + } + + /** + * Modify an object in the database. + */ + public void modify(String name, ModificationSet mods) + throws EBaseException { + try { + LDAPModificationSet ldapMods = new + LDAPModificationSet(); + Enumeration<?> e = mods.getModifications(); + + while (e.hasMoreElements()) { + Modification mod = (Modification) + e.nextElement(); + LDAPAttributeSet attrs = new LDAPAttributeSet(); + + mDBSystem.getRegistry().mapObject(null, + mod.getName(), mod.getValue(), attrs); + Enumeration<?> e0 = attrs.getAttributes(); + + while (e0.hasMoreElements()) { + ldapMods.add(toLdapModOp(mod.getOp()), + (LDAPAttribute) + e0.nextElement()); + } + } + + /*LogDoc + * + * @phase local ldap add + * @message DBSSession: begin LDAP modify <entry> + */ + mConn.modify(name, ldapMods); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + name + " " + e.toString())); + } + } + + private int toLdapModOp(int modOp) throws EBaseException { + switch (modOp) { + case Modification.MOD_ADD: + return LDAPModification.ADD; + + case Modification.MOD_DELETE: + return LDAPModification.DELETE; + + case Modification.MOD_REPLACE: + return LDAPModification.REPLACE; + } + throw new EBaseException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + Integer.toString(modOp))); + } + + /** + * Searchs for a list of objects that match the + * filter. + */ + public IDBSearchResults search(String base, String filter) + throws EBaseException { + return search(base, filter, null); + } + + @SuppressWarnings("unchecked") + public IDBSearchResults search(String base, String filter, int maxSize) + throws EBaseException { + try { + String ldapattrs[] = null; + String ldapfilter = + mDBSystem.getRegistry().getFilter(filter); + + LDAPSearchConstraints cons = new LDAPSearchConstraints(); + + cons.setMaxResults(maxSize); + + LDAPSearchResults res = mConn.search(base, + LDAPv2.SCOPE_ONE, ldapfilter, ldapattrs, false, cons); + + return new DBSearchResults(mDBSystem.getRegistry(), + res); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + // XXX error handling, should not raise exception if + // entry not found + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + e.toString())); + } + } + + @SuppressWarnings("unchecked") + public IDBSearchResults search(String base, String filter, int maxSize, int timeLimit) + throws EBaseException { + try { + String ldapattrs[] = null; + String ldapfilter = + mDBSystem.getRegistry().getFilter(filter); + + LDAPSearchConstraints cons = new LDAPSearchConstraints(); + + cons.setMaxResults(maxSize); + cons.setServerTimeLimit(timeLimit); + + LDAPSearchResults res = mConn.search(base, + LDAPv2.SCOPE_ONE, ldapfilter, ldapattrs, false, cons); + + return new DBSearchResults(mDBSystem.getRegistry(), + res); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + // XXX error handling, should not raise exception if + // entry not found + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + e.toString())); + } + } + + /** + * Retrieves a list of object that satifies the given + * filter. + */ + @SuppressWarnings("unchecked") + public IDBSearchResults search(String base, String filter, + String attrs[]) throws EBaseException { + try { + String ldapattrs[] = null; + + if (attrs != null) { + ldapattrs = mDBSystem.getRegistry( + ).getLDAPAttributes(attrs); + } + String ldapfilter = + mDBSystem.getRegistry().getFilter(filter); + + /*LogDoc + * + * @phase local ldap add + * @message DBSSession: begin LDAP search <filter> + */ + LDAPSearchConstraints cons = new LDAPSearchConstraints(); + + cons.setMaxResults(0); + + LDAPSearchResults res = mConn.search(base, + LDAPv2.SCOPE_ONE, ldapfilter, ldapattrs, false, cons); + + return new DBSearchResults(mDBSystem.getRegistry(), + res); + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + // XXX error handling, should not raise exception if + // entry not found + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + e.toString())); + } + } + + public LDAPSearchResults persistentSearch(String base, String filter, String attrs[]) + throws EBaseException { + try { + String ldapattrs[] = null; + if (attrs != null) { + ldapattrs = mDBSystem.getRegistry( + ).getLDAPAttributes(attrs); + } + String ldapfilter = + mDBSystem.getRegistry().getFilter(filter); + + Integer version = (Integer) (mConn.getOption(LDAPv2.PROTOCOL_VERSION)); + + // Only version 3 protocol supports persistent search. + if (version.intValue() == 2) { + mConn.setOption(LDAPv2.PROTOCOL_VERSION, Integer.valueOf(3)); + } + + int op = LDAPPersistSearchControl.MODIFY; + + boolean changesOnly = true; + boolean returnControls = true; + boolean isCritical = true; + LDAPPersistSearchControl persistCtrl = new + LDAPPersistSearchControl(op, changesOnly, + returnControls, isCritical); + + LDAPSearchConstraints cons = new LDAPSearchConstraints(); + cons.setBatchSize(0); + cons.setServerControls(persistCtrl); + + LDAPSearchResults res = mConn.search(base, + LDAPv2.SCOPE_ONE, ldapfilter, ldapattrs, false, cons); + return res; + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + // XXX error handling, should not raise exception if + // entry not found + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + e.toString())); + } + } + + public void abandon(LDAPSearchResults results) throws EBaseException { + try { + mConn.abandon(results); + + } catch (LDAPException e) { + if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + // XXX error handling, should not raise exception if + // entry not found + throw new EDBException(CMS.getUserMessage("CMS_DBS_LDAP_OP_FAILURE", + e.toString())); + } + } + + /** + * Retrieves a list of objects. + */ + public <T> IDBVirtualList<T> createVirtualList(String base, String filter, + String attrs[]) throws EBaseException { + return new DBVirtualList<T>(mDBSystem.getRegistry(), mConn, base, + filter, attrs); + } + + /** + * Retrieves a list of objects. + */ + public <T> IDBVirtualList<T> createVirtualList(String base, String filter, + String attrs[], String sortKey[]) throws EBaseException { + return new DBVirtualList<T>(mDBSystem.getRegistry(), mConn, base, + filter, attrs, sortKey); + } + + /** + * Retrieves a list of objects. + */ + public IDBVirtualList<?> createVirtualList(String base, String filter, + String attrs[], String sortKey) throws EBaseException { + return new DBVirtualList<Object>(mDBSystem.getRegistry(), mConn, base, + filter, attrs, sortKey); + } + + /** + * Retrieves a list of objects. + */ + public IDBVirtualList<?> createVirtualList(String base, String filter, + String attrs[], String sortKey[], int pageSize) throws EBaseException { + return new DBVirtualList<Object>(mDBSystem.getRegistry(), mConn, base, + filter, attrs, sortKey, pageSize); + } + + /** + * Retrieves a list of objects. + */ + public IDBVirtualList<Object> createVirtualList(String base, String filter, + String attrs[], String sortKey, int pageSize) throws EBaseException { + return new DBVirtualList<Object>(mDBSystem.getRegistry(), mConn, base, + filter, attrs, sortKey, pageSize); + } + + public IDBVirtualList<Object> createVirtualList(String base, String filter, + String attrs[], String startFrom, String sortKey, int pageSize) throws EBaseException { + return new DBVirtualList<Object>(mDBSystem.getRegistry(), mConn, base, + filter, attrs, startFrom, sortKey, pageSize); + + } + + /** + * Releases object to this interface. This allows us to + * use memory more efficiently. + */ + public void release(Object obj) { + // not implemented + } + +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBSUtil.java b/base/common/src/com/netscape/cmscore/dbs/DBSUtil.java new file mode 100644 index 000000000..7c551b141 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBSUtil.java @@ -0,0 +1,49 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +/** + * A class represents ann attribute mapper that maps + * a Java BigInteger object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DBSUtil { + + public static String longToDB(long val) { + String s = Long.toString(val); + // prefix with 2 digits that represents + // the length of the value + int l = s.length(); + String dbVal = ""; + + if (s.length() < 10) { + dbVal = "0"; + } + return dbVal + Integer.toString(l) + s; + } + + public static long longFromDB(String dbLong) { + // remove the first 2 digits + String s = dbLong.substring(2); + + return Long.parseLong(s); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBSearchResults.java b/base/common/src/com/netscape/cmscore/dbs/DBSearchResults.java new file mode 100644 index 000000000..0621701b0 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBSearchResults.java @@ -0,0 +1,93 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; + +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents the search results. A search + * results object contain a enumeration of + * Java objects that are just read from the database. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DBSearchResults implements IDBSearchResults { + + private IDBRegistry mRegistry = null; + private Enumeration<Object> mRes = null; + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs search results. + */ + public DBSearchResults(IDBRegistry registry, Enumeration<Object> res) { + mRegistry = registry; + mRes = res; + } + + /** + * Checks if any element is available. + */ + public boolean hasMoreElements() { + return mRes.hasMoreElements(); + } + + /** + * Retrieves next element. + */ + public Object nextElement() { + LDAPEntry entry = null; + + try { + Object o = mRes.nextElement(); + + if (o instanceof LDAPEntry) { + entry = (LDAPEntry) o; + return mRegistry.createObject(entry.getAttributeSet()); + } else { + if (o instanceof LDAPException) + ; + // doing nothing because the last object in the search + // results is always LDAPException + else + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, "DBSearchResults: result format error class=" + o.getClass().getName()); + } + } catch (Exception e) { + + /*LogDoc + * + * @phase local ldap search + * @reason failed to get next element + * @message DBSearchResults: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, "DBSearchResults: " + e.toString()); + } + return null; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java b/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java new file mode 100644 index 000000000..4bc5b6471 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBSubsystem.java @@ -0,0 +1,948 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Hashtable; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSchema; +import netscape.ldap.LDAPAttributeSet; +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPException; +import netscape.ldap.LDAPModification; +import netscape.ldap.LDAPObjectClassSchema; +import netscape.ldap.LDAPSchema; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPv3; +import netscape.security.x509.CertificateValidity; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.EDBNotAvailException; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.repository.IRepositoryRecord; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.ldap.ELdapServerDownException; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmscore.base.PropConfigStore; +import com.netscape.cmscore.ldapconn.LdapAuthInfo; +import com.netscape.cmscore.ldapconn.LdapBoundConnFactory; +import com.netscape.cmscore.ldapconn.LdapConnInfo; + +/** + * A class represents the database subsystem that manages + * the backend data storage. + * + * This subsystem maintains multiple sessions that allows + * operations to be performed, and provide a registry + * where all the schema information is stored. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DBSubsystem implements IDBSubsystem { + + public static String ID = IDBSubsystem.SUB_ID; + + private IConfigStore mConfig = null; + private IConfigStore mDBConfig = null; + private LdapBoundConnFactory mLdapConnFactory = null; + private DBRegistry mRegistry = null; + private String mBaseDN = null; + private ISubsystem mOwner = null; + + private Hashtable<String, String>[] mRepos = null; + + private BigInteger mNextSerialConfig = null; + private boolean mEnableSerialMgmt = false; + + private static final String PEOPLE_DN = "ou=people"; + private static final String GROUPS_DN = "ou=groups"; + private static final String REQUESTS_DN = "ou=requests"; + private static final String XCERTS_DN = "cn=crossCerts"; + private static final String BASEDN = "o=netscapeCertificateServer"; + private static final String DEFAULT_DATABASE = "userRoot"; + private static final String AT_OC = "objectclass"; + private static final String AT_O = "o"; + private static final String AT_OU = "ou"; + private static final String CA_DN = "ou=ca"; + private static final String CR_DN = "ou=certificateRepository, ou=ca"; + private static final String CRL_DN = "ou=crlIssuingPoints, ou=ca"; + private static final String CA_REQUESTS_DN = "ou=ca, ou=requests"; + private static final String KRA_DN = "ou=kra"; + private static final String KR_DN = "ou=keyRepository, ou=kra"; + private static final String KRA_REQUESTS_DN = "ou=kra, ou=requests"; + private static final String REPLICA_DN = "ou=replica"; + private static final String PROP_ENABLE_SERIAL_NUMBER_RECOVERY = + "enableSerialNumberRecovery"; + // This value is only equal to the next Serial number that the CA's + // going to issue when cms just start up or it's just set from console. + // It doesn't record the next serial number at other time when cms's + // runing not to increase overhead when issuing certs. + private static final String PROP_NEXT_SERIAL_NUMBER = + "nextSerialNumber"; + private static final String PROP_MIN_SERIAL_NUMBER = "beginSerialNumber"; + private static final String PROP_MAX_SERIAL_NUMBER = "endSerialNumber"; + private static final String PROP_NEXT_MIN_SERIAL_NUMBER = "nextBeginSerialNumber"; + private static final String PROP_NEXT_MAX_SERIAL_NUMBER = "nextEndSerialNumber"; + private static final String PROP_SERIAL_LOW_WATER_MARK = "serialLowWaterMark"; + private static final String PROP_SERIAL_INCREMENT = "serialIncrement"; + private static final String PROP_SERIAL_BASEDN = "serialDN"; + private static final String PROP_SERIAL_RANGE_DN = "serialRangeDN"; + + private static final String PROP_MIN_REQUEST_NUMBER = "beginRequestNumber"; + private static final String PROP_MAX_REQUEST_NUMBER = "endRequestNumber"; + private static final String PROP_NEXT_MIN_REQUEST_NUMBER = "nextBeginRequestNumber"; + private static final String PROP_NEXT_MAX_REQUEST_NUMBER = "nextEndRequestNumber"; + private static final String PROP_REQUEST_LOW_WATER_MARK = "requestLowWaterMark"; + private static final String PROP_REQUEST_INCREMENT = "requestIncrement"; + private static final String PROP_REQUEST_BASEDN = "requestDN"; + private static final String PROP_REQUEST_RANGE_DN = "requestRangeDN"; + + private static final String PROP_MIN_REPLICA_NUMBER = "beginReplicaNumber"; + private static final String PROP_MAX_REPLICA_NUMBER = "endReplicaNumber"; + private static final String PROP_NEXT_MIN_REPLICA_NUMBER = "nextBeginReplicaNumber"; + private static final String PROP_NEXT_MAX_REPLICA_NUMBER = "nextEndReplicaNumber"; + private static final String PROP_REPLICA_LOW_WATER_MARK = "replicaLowWaterMark"; + private static final String PROP_REPLICA_INCREMENT = "replicaIncrement"; + private static final String PROP_REPLICA_BASEDN = "replicaDN"; + private static final String PROP_REPLICA_RANGE_DN = "replicaRangeDN"; + + private static final String PROP_INFINITE_SERIAL_NUMBER = "1000000000"; + private static final String PROP_INFINITE_REQUEST_NUMBER = "1000000000"; + private static final String PROP_INFINITE_REPLICA_NUMBER = "1000"; + private static final String PROP_BASEDN = "basedn"; + private static final String PROP_LDAP = "ldap"; + private static final String PROP_NEXT_RANGE = "nextRange"; + private static final String PROP_ENABLE_SERIAL_MGMT = "enableSerialManagement"; + + // hash keys + private static final String NAME = "name"; + private static final String PROP_MIN = "min"; + private static final String PROP_MIN_NAME = "min_name"; + private static final String PROP_MAX = "max"; + private static final String PROP_MAX_NAME = "max_name"; + private static final String PROP_NEXT_MIN = "next_min"; + private static final String PROP_NEXT_MIN_NAME = "next_min_name"; + private static final String PROP_NEXT_MAX = "next_max"; + private static final String PROP_NEXT_MAX_NAME = "next_max_name"; + private static final String PROP_LOW_WATER_MARK = "lowWaterMark"; + private static final String PROP_LOW_WATER_MARK_NAME = "lowWaterMark_name"; + private static final String PROP_INCREMENT = "increment"; + private static final String PROP_INCREMENT_NAME = "increment_name"; + private static final String PROP_RANGE_DN = "rangeDN"; + + private static final BigInteger BI_ONE = new BigInteger("1"); + + private ILogger mLogger = null; + + // singleton enforcement + + private static IDBSubsystem mInstance = new DBSubsystem(); + + public static IDBSubsystem getInstance() { + return mInstance; + } + + /** + * This method is used for unit tests. It allows the underlying instance + * to be stubbed out. + * + * @param dbSubsystem The stubbed out subsystem to override with. + */ + public static void setInstance(IDBSubsystem dbSubsystem) { + mInstance = dbSubsystem; + } + + // end singleton enforcement. + + /** + * Constructs database subsystem. + */ + private DBSubsystem() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return IDBSubsystem.SUB_ID; + } + + /** + * Sets subsystem identifier. + */ + public void setId(String id) throws EBaseException { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")); + } + + public boolean enableSerialNumberRecovery() { + try { + return mDBConfig.getBoolean( + PROP_ENABLE_SERIAL_NUMBER_RECOVERY, true); + } catch (EBaseException e) { + // by default + return true; + } + } + + public boolean getEnableSerialMgmt() { + return mEnableSerialMgmt; + } + + public void setEnableSerialMgmt(boolean v) + throws EBaseException { + if (v) { + CMS.debug("DBSubsystem: Enabling Serial Number Management"); + } else { + CMS.debug("DBSubsystem: Disabling Serial Number Management"); + } + + mDBConfig.putBoolean(PROP_ENABLE_SERIAL_MGMT, v); + IConfigStore rootStore = getOwner().getConfigStore(); + rootStore.commit(false); + mEnableSerialMgmt = v; + } + + public BigInteger getNextSerialConfig() { + return mNextSerialConfig; + } + + public void setNextSerialConfig(BigInteger serial) + throws EBaseException { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_INFO, "DBSubsystem: " + + "Setting next serial number: 0x" + serial.toString(16)); + mDBConfig.putString(PROP_NEXT_SERIAL_NUMBER, + serial.toString(16)); + } + + /** + * Gets minimum serial number limit in config file + * + * @param repo repo identifier + * @return min serial number + */ + public String getMinSerialConfig(int repo) { + return mRepos[repo].get(PROP_MIN); + } + + /** + * Gets maximum serial number limit in config file + * + * @param repo repo identifier + * @return max serial number + */ + public String getMaxSerialConfig(int repo) { + return mRepos[repo].get(PROP_MAX); + } + + /** + * Gets minimum serial number limit in next range in config file + * + * @param repo repo identifier + * @return min serial number in next range + */ + public String getNextMinSerialConfig(int repo) { + String ret = mRepos[repo].get(PROP_NEXT_MIN); + if (ret.equals("-1")) { + return null; + } else { + return ret; + } + } + + /** + * Gets maximum serial number limit in next range in config file + * + * @param repo repo identifier + * @return max serial number in next range + */ + public String getNextMaxSerialConfig(int repo) { + String ret = mRepos[repo].get(PROP_NEXT_MAX); + if (ret.equals("-1")) { + return null; + } else { + return ret; + } + } + + /** + * Gets low water mark limit in config file + * + * @param repo repo identifier + * @return low water mark + */ + public String getLowWaterMarkConfig(int repo) { + return mRepos[repo].get(PROP_LOW_WATER_MARK); + } + + /** + * Gets range increment for next range in config file + * + * @param repo repo identifier + * @return range increment + */ + public String getIncrementConfig(int repo) { + return mRepos[repo].get(PROP_INCREMENT); + } + + /** + * Sets maximum serial number limit in config file + * + * @param repo repo identifier + * @param serial max serial number + * @exception EBaseException failed to set + */ + public void setMaxSerialConfig(int repo, String serial) + throws EBaseException { + Hashtable<String, String> h = mRepos[repo]; + CMS.debug("DBSubsystem: Setting max serial number for " + h.get(NAME) + ": " + serial); + + //persist to file + mDBConfig.putString((String) h.get(PROP_MAX_NAME), serial); + IConfigStore rootStore = getOwner().getConfigStore(); + rootStore.commit(false); + + h.put(PROP_MAX, serial); + mRepos[repo] = h; + } + + /** + * Sets minimum serial number limit in config file + * + * @param repo repo identifier + * @param serial min serial number + * @exception EBaseException failed to set + */ + public void setMinSerialConfig(int repo, String serial) + throws EBaseException { + Hashtable<String, String> h = mRepos[repo]; + CMS.debug("DBSubsystem: Setting min serial number for " + h.get(NAME) + ": " + serial); + + //persist to file + mDBConfig.putString((String) h.get(PROP_MIN_NAME), serial); + IConfigStore rootStore = getOwner().getConfigStore(); + rootStore.commit(false); + + h.put(PROP_MIN, serial); + mRepos[repo] = h; + } + + /** + * Sets maximum serial number limit for next range in config file + * + * @param repo repo identifier + * @param serial max serial number for next range + * @exception EBaseException failed to set + */ + public void setNextMaxSerialConfig(int repo, String serial) + throws EBaseException { + Hashtable<String, String> h = mRepos[repo]; + if (serial == null) { + CMS.debug("DBSubsystem: Removing next max " + h.get(NAME) + " number"); + mDBConfig.remove((String) h.get(PROP_NEXT_MAX_NAME)); + } else { + CMS.debug("DBSubsystem: Setting next max " + h.get(NAME) + " number: " + serial); + mDBConfig.putString((String) h.get(PROP_NEXT_MAX_NAME), serial); + } + IConfigStore rootStore = getOwner().getConfigStore(); + rootStore.commit(false); + if (serial == null) { + h.remove(PROP_NEXT_MAX); + } else { + h.put(PROP_NEXT_MAX, serial); + } + mRepos[repo] = h; + } + + /** + * Sets minimum serial number limit for next range in config file + * + * @param repo repo identifier + * @param serial min serial number for next range + * @exception EBaseException failed to set + */ + public void setNextMinSerialConfig(int repo, String serial) + throws EBaseException { + Hashtable<String, String> h = mRepos[repo]; + if (serial == null) { + CMS.debug("DBSubsystem: Removing next min " + h.get(NAME) + " number"); + mDBConfig.remove((String) h.get(PROP_NEXT_MIN_NAME)); + } else { + CMS.debug("DBSubsystem: Setting next min " + h.get(NAME) + " number: " + serial); + mDBConfig.putString((String) h.get(PROP_NEXT_MIN_NAME), serial); + } + IConfigStore rootStore = getOwner().getConfigStore(); + rootStore.commit(false); + if (serial == null) { + h.remove(PROP_NEXT_MIN); + } else { + h.put(PROP_NEXT_MIN, serial); + } + mRepos[repo] = h; + } + + /** + * Gets start of next range from database. + * Increments the nextRange attribute and allocates + * this range to the current instance by creating a pkiRange object. + * + * @param repo repo identifier + * @return start of next range + */ + public String getNextRange(int repo) { + LDAPConnection conn = null; + String nextRange = null; + try { + Hashtable<String, String> h = mRepos[repo]; + conn = mLdapConnFactory.getConn(); + String dn = (String) h.get(PROP_BASEDN) + "," + mBaseDN; + String rangeDN = (String) h.get(PROP_RANGE_DN) + "," + mBaseDN; + + LDAPEntry entry = conn.read(dn); + LDAPAttribute attr = entry.getAttribute(PROP_NEXT_RANGE); + nextRange = (String) attr.getStringValues().nextElement(); + + BigInteger nextRangeNo = new BigInteger(nextRange); + BigInteger incrementNo = new BigInteger((String) h.get(PROP_INCREMENT)); + // To make sure attrNextRange always increments, first delete the current value and then + // increment. Two operations in the same transaction + LDAPAttribute attrNextRange = new LDAPAttribute(PROP_NEXT_RANGE, nextRangeNo.add(incrementNo).toString()); + LDAPModification[] mods = { + new LDAPModification(LDAPModification.DELETE, attr), + new LDAPModification(LDAPModification.ADD, attrNextRange) }; + conn.modify(dn, mods); + + // Add new range object + String endRange = nextRangeNo.add(incrementNo).subtract(BI_ONE).toString(); + LDAPAttributeSet attrs = new LDAPAttributeSet(); + attrs.add(new LDAPAttribute("objectClass", "top")); + attrs.add(new LDAPAttribute("objectClass", "pkiRange")); + attrs.add(new LDAPAttribute("beginRange", nextRange)); + attrs.add(new LDAPAttribute("endRange", endRange)); + attrs.add(new LDAPAttribute("cn", nextRange)); + attrs.add(new LDAPAttribute("host", CMS.getEESSLHost())); + attrs.add(new LDAPAttribute("securePort", CMS.getEESSLPort())); + String dn2 = "cn=" + nextRange + "," + rangeDN; + LDAPEntry rangeEntry = new LDAPEntry(dn2, attrs); + conn.add(rangeEntry); + } catch (Exception e) { + CMS.debug("DBSubsystem: getNextRange. Unable to provide next range :" + e); + e.printStackTrace(); + nextRange = null; + } finally { + try { + if ((conn != null) && (mLdapConnFactory != null)) { + CMS.debug("Releasing ldap connection"); + mLdapConnFactory.returnConn(conn); + } + } catch (Exception e) { + CMS.debug("Error releasing the ldap connection" + e.toString()); + } + } + return nextRange; + } + + /** + * Determines if a range conflict has been observed in database. + * If so, delete the conflict entry and remove the next range. + * When the next number is requested, if the number of certs is still + * below the low water mark, then a new range will be requested. + * + * @param repo repo identifier + * @return true if range conflict, false otherwise + */ + public boolean hasRangeConflict(int repo) { + LDAPConnection conn = null; + boolean conflict = false; + try { + String nextRangeStart = getNextMinSerialConfig(repo); + if (nextRangeStart == null) { + return false; + } + Hashtable<String, String> h = mRepos[repo]; + conn = mLdapConnFactory.getConn(); + String rangedn = (String) h.get(PROP_RANGE_DN) + "," + mBaseDN; + String filter = "(&(nsds5ReplConflict=*)(objectClass=pkiRange)(host= " + + CMS.getEESSLHost() + ")(SecurePort=" + CMS.getEESSLPort() + + ")(beginRange=" + nextRangeStart + "))"; + LDAPSearchResults results = conn.search(rangedn, LDAPv3.SCOPE_SUB, + filter, null, false); + + while (results.hasMoreElements()) { + conflict = true; + LDAPEntry entry = results.next(); + String dn = entry.getDN(); + CMS.debug("Deleting conflict entry:" + dn); + conn.delete(dn); + } + } catch (Exception e) { + CMS.debug("DBSubsystem: hasRangeConflict. Error while checking next range." + e); + e.printStackTrace(); + } finally { + try { + if ((conn != null) && (mLdapConnFactory != null)) { + CMS.debug("Releasing ldap connection"); + mLdapConnFactory.returnConn(conn); + } + } catch (Exception e) { + CMS.debug("Error releasing the ldap connection" + e.toString()); + } + } + return conflict; + } + + public ISubsystem getOwner() { + return mOwner; + } + + /** + * Initializes the internal registery. Connects to the + * data source, and create a pool of connection of which + * applications can use. Optionally, check the integrity + * of the database. + */ + @SuppressWarnings("unchecked") + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + + mLogger = CMS.getLogger(); + mDBConfig = config; + mRepos = new Hashtable[IDBSubsystem.NUM_REPOS]; + + mConfig = config.getSubStore(PROP_LDAP); + IConfigStore tmpConfig = null; + try { + mBaseDN = mConfig.getString(PROP_BASEDN, "o=NetscapeCertificateServer"); + + mOwner = owner; + + mNextSerialConfig = new BigInteger(mDBConfig.getString( + PROP_NEXT_SERIAL_NUMBER, "0"), 16); + + mEnableSerialMgmt = mDBConfig.getBoolean(PROP_ENABLE_SERIAL_MGMT, false); + + // populate the certs hash entry + Hashtable<String, String> certs = new Hashtable<String, String>(); + certs.put(NAME, "certs"); + certs.put(PROP_BASEDN, mDBConfig.getString(PROP_SERIAL_BASEDN, "")); + certs.put(PROP_RANGE_DN, mDBConfig.getString(PROP_SERIAL_RANGE_DN, "")); + + certs.put(PROP_MIN_NAME, PROP_MIN_SERIAL_NUMBER); + certs.put(PROP_MIN, mDBConfig.getString( + PROP_MIN_SERIAL_NUMBER, "0")); + + certs.put(PROP_MAX_NAME, PROP_MAX_SERIAL_NUMBER); + certs.put(PROP_MAX, mDBConfig.getString( + PROP_MAX_SERIAL_NUMBER, PROP_INFINITE_SERIAL_NUMBER)); + + certs.put(PROP_NEXT_MIN_NAME, PROP_NEXT_MIN_SERIAL_NUMBER); + certs.put(PROP_NEXT_MIN, mDBConfig.getString( + PROP_NEXT_MIN_SERIAL_NUMBER, "-1")); + + certs.put(PROP_NEXT_MAX_NAME, PROP_NEXT_MAX_SERIAL_NUMBER); + certs.put(PROP_NEXT_MAX, mDBConfig.getString( + PROP_NEXT_MAX_SERIAL_NUMBER, "-1")); + + certs.put(PROP_LOW_WATER_MARK_NAME, PROP_SERIAL_LOW_WATER_MARK); + certs.put(PROP_LOW_WATER_MARK, mDBConfig.getString( + PROP_SERIAL_LOW_WATER_MARK, "5000")); + + certs.put(PROP_INCREMENT_NAME, PROP_SERIAL_INCREMENT); + certs.put(PROP_INCREMENT, mDBConfig.getString( + PROP_SERIAL_INCREMENT, PROP_INFINITE_SERIAL_NUMBER)); + + mRepos[CERTS] = certs; + + // populate the requests hash entry + Hashtable<String, String> requests = new Hashtable<String, String>(); + requests.put(NAME, "requests"); + requests.put(PROP_BASEDN, mDBConfig.getString(PROP_REQUEST_BASEDN, "")); + requests.put(PROP_RANGE_DN, mDBConfig.getString(PROP_REQUEST_RANGE_DN, "")); + + requests.put(PROP_MIN_NAME, PROP_MIN_REQUEST_NUMBER); + requests.put(PROP_MIN, mDBConfig.getString( + PROP_MIN_REQUEST_NUMBER, "0")); + + requests.put(PROP_MAX_NAME, PROP_MAX_REQUEST_NUMBER); + requests.put(PROP_MAX, mDBConfig.getString( + PROP_MAX_REQUEST_NUMBER, PROP_INFINITE_REQUEST_NUMBER)); + + requests.put(PROP_NEXT_MIN_NAME, PROP_NEXT_MIN_REQUEST_NUMBER); + requests.put(PROP_NEXT_MIN, mDBConfig.getString( + PROP_NEXT_MIN_REQUEST_NUMBER, "-1")); + + requests.put(PROP_NEXT_MAX_NAME, PROP_NEXT_MAX_REQUEST_NUMBER); + requests.put(PROP_NEXT_MAX, mDBConfig.getString( + PROP_NEXT_MAX_REQUEST_NUMBER, "-1")); + + requests.put(PROP_LOW_WATER_MARK_NAME, PROP_REQUEST_LOW_WATER_MARK); + requests.put(PROP_LOW_WATER_MARK, mDBConfig.getString( + PROP_REQUEST_LOW_WATER_MARK, "5000")); + + requests.put(PROP_INCREMENT_NAME, PROP_REQUEST_INCREMENT); + requests.put(PROP_INCREMENT, mDBConfig.getString( + PROP_REQUEST_INCREMENT, PROP_INFINITE_REQUEST_NUMBER)); + + mRepos[REQUESTS] = requests; + + // populate replica ID hash entry + Hashtable<String, String> replicaID = new Hashtable<String, String>(); + replicaID.put(NAME, "requests"); + replicaID.put(PROP_BASEDN, mDBConfig.getString(PROP_REPLICA_BASEDN, "")); + replicaID.put(PROP_RANGE_DN, mDBConfig.getString(PROP_REPLICA_RANGE_DN, "")); + + replicaID.put(PROP_MIN_NAME, PROP_MIN_REPLICA_NUMBER); + replicaID.put(PROP_MIN, mDBConfig.getString( + PROP_MIN_REPLICA_NUMBER, "1")); + + replicaID.put(PROP_MAX_NAME, PROP_MAX_REPLICA_NUMBER); + replicaID.put(PROP_MAX, mDBConfig.getString( + PROP_MAX_REPLICA_NUMBER, PROP_INFINITE_REPLICA_NUMBER)); + + replicaID.put(PROP_NEXT_MIN_NAME, PROP_NEXT_MIN_REPLICA_NUMBER); + replicaID.put(PROP_NEXT_MIN, mDBConfig.getString( + PROP_NEXT_MIN_REPLICA_NUMBER, "-1")); + + replicaID.put(PROP_NEXT_MAX_NAME, PROP_NEXT_MAX_REPLICA_NUMBER); + replicaID.put(PROP_NEXT_MAX, mDBConfig.getString( + PROP_NEXT_MAX_REPLICA_NUMBER, "-1")); + + replicaID.put(PROP_LOW_WATER_MARK_NAME, PROP_REPLICA_LOW_WATER_MARK); + replicaID.put(PROP_LOW_WATER_MARK, mDBConfig.getString( + PROP_REPLICA_LOW_WATER_MARK, "10")); + + replicaID.put(PROP_INCREMENT_NAME, PROP_REPLICA_INCREMENT); + replicaID.put(PROP_INCREMENT, mDBConfig.getString( + PROP_REPLICA_INCREMENT, PROP_INFINITE_REPLICA_NUMBER)); + + mRepos[REPLICA_ID] = replicaID; + + // initialize registry + mRegistry = new DBRegistry(); + mRegistry.init(this, null); + + // initialize LDAP connection factory + // by default return error if server is down at startup time. + mLdapConnFactory = new LdapBoundConnFactory(true); + tmpConfig = (IConfigStore) (((PropConfigStore) mConfig).clone()); + + tmpConfig.putString(PROP_BASEDN, mBaseDN); + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + return; + throw e; + } + + try { + mLdapConnFactory.init(tmpConfig); + } catch (ELdapServerDownException e) { + if (CMS.isPreOpMode()) + return; + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + } catch (ELdapException ex) { + if (CMS.isPreOpMode()) + return; + throw new EDBException(CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_ERROR", ex.toString())); + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + return; + throw e; + } + + try { + // registers CMS database attributes + IDBRegistry reg = getRegistry(); + + String certRecordOC[] = new String[2]; + + certRecordOC[0] = CertDBSchema.LDAP_OC_TOP; + certRecordOC[1] = CertDBSchema.LDAP_OC_CERT_RECORD; + + if (!reg.isObjectClassRegistered(CertRecord.class.getName())) { + reg.registerObjectClass(CertRecord.class.getName(), + certRecordOC); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_ID)) { + reg.registerAttribute(CertRecord.ATTR_ID, new + BigIntegerMapper(CertDBSchema.LDAP_ATTR_SERIALNO)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_META_INFO)) { + reg.registerAttribute(CertRecord.ATTR_META_INFO, new + MetaInfoMapper(CertDBSchema.LDAP_ATTR_META_INFO)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_REVO_INFO)) { + reg.registerAttribute(CertRecord.ATTR_REVO_INFO, new + RevocationInfoMapper()); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_X509CERT)) { + reg.registerAttribute(CertRecord.ATTR_X509CERT, new + X509CertImplMapper()); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_CERT_STATUS)) { + reg.registerAttribute(CertRecord.ATTR_CERT_STATUS, new + StringMapper(CertDBSchema.LDAP_ATTR_CERT_STATUS)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_AUTO_RENEW)) { + reg.registerAttribute(CertRecord.ATTR_AUTO_RENEW, new + StringMapper(CertDBSchema.LDAP_ATTR_AUTO_RENEW)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_CREATE_TIME)) { + reg.registerAttribute(CertRecord.ATTR_CREATE_TIME, new + DateMapper(CertDBSchema.LDAP_ATTR_CREATE_TIME)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_MODIFY_TIME)) { + reg.registerAttribute(CertRecord.ATTR_MODIFY_TIME, new + DateMapper(CertDBSchema.LDAP_ATTR_MODIFY_TIME)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_ISSUED_BY)) { + reg.registerAttribute(CertRecord.ATTR_ISSUED_BY, new + StringMapper(CertDBSchema.LDAP_ATTR_ISSUED_BY)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_REVOKED_BY)) { + reg.registerAttribute(CertRecord.ATTR_REVOKED_BY, new + StringMapper(CertDBSchema.LDAP_ATTR_REVOKED_BY)); + } + if (!reg.isAttributeRegistered(CertRecord.ATTR_REVOKED_ON)) { + reg.registerAttribute(CertRecord.ATTR_REVOKED_ON, new + DateMapper(CertDBSchema.LDAP_ATTR_REVOKED_ON)); + } + + if (!reg.isAttributeRegistered(CertificateValidity.NOT_AFTER)) { + reg.registerAttribute(CertificateValidity.NOT_AFTER, new + DateMapper(CertDBSchema.LDAP_ATTR_NOT_AFTER)); + } + + if (!reg.isAttributeRegistered(CertificateValidity.NOT_BEFORE)) { + reg.registerAttribute(CertificateValidity.NOT_BEFORE, new + DateMapper(CertDBSchema.LDAP_ATTR_NOT_BEFORE)); + } + + String crlRecordOC[] = new String[2]; + + crlRecordOC[0] = CRLDBSchema.LDAP_OC_TOP; + crlRecordOC[1] = CRLDBSchema.LDAP_OC_CRL_RECORD; + reg.registerObjectClass(CRLIssuingPointRecord.class.getName(), + crlRecordOC); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_ID, new + StringMapper(CRLDBSchema.LDAP_ATTR_CRL_ID)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL_NUMBER, new + BigIntegerMapper(CRLDBSchema.LDAP_ATTR_CRL_NUMBER)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_DELTA_NUMBER, new + BigIntegerMapper(CRLDBSchema.LDAP_ATTR_DELTA_NUMBER)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL_SIZE, new + LongMapper(CRLDBSchema.LDAP_ATTR_CRL_SIZE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_DELTA_SIZE, new + LongMapper(CRLDBSchema.LDAP_ATTR_DELTA_SIZE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_THIS_UPDATE, new + DateMapper(CRLDBSchema.LDAP_ATTR_THIS_UPDATE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_NEXT_UPDATE, new + DateMapper(CRLDBSchema.LDAP_ATTR_NEXT_UPDATE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_FIRST_UNSAVED, new + StringMapper(CRLDBSchema.LDAP_ATTR_FIRST_UNSAVED)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL, new + ByteArrayMapper(CRLDBSchema.LDAP_ATTR_CRL)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_DELTA_CRL, new + ByteArrayMapper(CRLDBSchema.LDAP_ATTR_DELTA_CRL)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CA_CERT, new + ByteArrayMapper(CRLDBSchema.LDAP_ATTR_CA_CERT)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_CRL_CACHE, new + ObjectStreamMapper(CRLDBSchema.LDAP_ATTR_CRL_CACHE)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_REVOKED_CERTS, new + ObjectStreamMapper(CRLDBSchema.LDAP_ATTR_REVOKED_CERTS)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_UNREVOKED_CERTS, new + ObjectStreamMapper(CRLDBSchema.LDAP_ATTR_UNREVOKED_CERTS)); + reg.registerAttribute(ICRLIssuingPointRecord.ATTR_EXPIRED_CERTS, new + ObjectStreamMapper(CRLDBSchema.LDAP_ATTR_EXPIRED_CERTS)); + + if (!reg.isObjectClassRegistered( + RepositoryRecord.class.getName())) { + String repRecordOC[] = new String[2]; + + repRecordOC[0] = RepositorySchema.LDAP_OC_TOP; + repRecordOC[1] = RepositorySchema.LDAP_OC_REPOSITORY; + reg.registerObjectClass( + RepositoryRecord.class.getName(), repRecordOC); + } + if (!reg.isAttributeRegistered(IRepositoryRecord.ATTR_SERIALNO)) { + reg.registerAttribute(IRepositoryRecord.ATTR_SERIALNO, + new BigIntegerMapper(RepositorySchema.LDAP_ATTR_SERIALNO)); + } + if (!reg.isAttributeRegistered(IRepositoryRecord.ATTR_PUB_STATUS)) { + reg.registerAttribute(IRepositoryRecord.ATTR_PUB_STATUS, + new StringMapper(RepositorySchema.LDAP_ATTR_PUB_STATUS)); + } + + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + return; + throw e; + } + } + + /** + * Starts up this service. + */ + public void startup() throws EBaseException { + } + + /** + * Retrieves configuration store. + */ + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Retrieves base DN of backend database. + */ + public String getBaseDN() { + return mBaseDN; + } + + /** + * Retrieves LDAP connection info (host, port, secure) + */ + public LdapConnInfo getLdapConnInfo() { + if (mLdapConnFactory != null) + return mLdapConnFactory.getConnInfo(); + return null; + } + + public LdapAuthInfo getLdapAuthInfo() { + if (mLdapConnFactory != null) + return mLdapConnFactory.getAuthInfo(); + return null; + } + + /** + * Shutdowns this subsystem gracefully. + */ + public void shutdown() { + try { + if (mLdapConnFactory != null) { + mLdapConnFactory.reset(); + mLdapConnFactory = null; + } + } catch (ELdapException e) { + + /*LogDoc + * + * @phase shutdown server + * @reason shutdown db subsystem + * @message DBSubsystem: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, + ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + if (mRegistry != null) + mRegistry.shutdown(); + } + + /** + * Retrieves the registry. + */ + public IDBRegistry getRegistry() { + return mRegistry; + } + + /** + * Creates a database session. + */ + public IDBSSession createSession() throws EDBException { + LDAPConnection conn = null; + + try { + conn = mLdapConnFactory.getConn(); + + String schemaAdded = mDBConfig.getString("newSchemaEntryAdded", ""); + + if (schemaAdded.equals("")) { + LDAPSchema dirSchema = new LDAPSchema(); + + // create new attribute: userType + dirSchema.fetchSchema(conn); + LDAPAttributeSchema userType = dirSchema.getAttribute("usertype"); + + if (userType == null) { + userType = new LDAPAttributeSchema("usertype", "usertype-oid", + "Distinguish whether the user is administrator, agent or subsystem.", + LDAPAttributeSchema.cis, false); + userType.add(conn); + } + + // create new objectclass: cmsuser + dirSchema.fetchSchema(conn); + LDAPObjectClassSchema newObjClass = dirSchema.getObjectClass("cmsuser"); + String[] requiredAttrs = { "usertype" }; + String[] optionalAttrs = new String[0]; + + if (newObjClass == null) { + newObjClass = new LDAPObjectClassSchema("cmsuser", "cmsuser-oid", + "top", "CMS User", requiredAttrs, optionalAttrs); + newObjClass.add(conn); + } + mDBConfig.putString("newSchemaEntryAdded", "true"); + IConfigStore rootStore = getOwner().getConfigStore(); + + rootStore.commit(false); + } + } catch (ELdapException e) { + if (e instanceof ELdapServerDownException) { + throw new EDBNotAvailException( + CMS.getUserMessage("CMS_DBS_INTERNAL_DIR_UNAVAILABLE")); + } + + /*LogDoc + * + * @phase create db session + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_CONN_ERROR", e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_CONNECT_LDAP_FAILED", e.toString())); + } catch (LDAPException e) { + if (e.getLDAPResultCode() != 20) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_SCHEMA_ERROR", e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_ADD_ENTRY_FAILED", e.toString())); + } + } catch (EBaseException e) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_CONF_ERROR", + e.toString())); + } + return new DBSSession(this, conn); + } + + public void returnConn(LDAPConnection conn) { + mLdapConnFactory.returnConn(conn); + } + +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DBVirtualList.java b/base/common/src/com/netscape/cmscore/dbs/DBVirtualList.java new file mode 100644 index 000000000..574ab41c0 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DBVirtualList.java @@ -0,0 +1,782 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Arrays; +import java.util.Vector; + +import netscape.ldap.LDAPConnection; +import netscape.ldap.LDAPControl; +import netscape.ldap.LDAPEntry; +import netscape.ldap.LDAPSearchConstraints; +import netscape.ldap.LDAPSearchResults; +import netscape.ldap.LDAPSortKey; +import netscape.ldap.controls.LDAPSortControl; +import netscape.ldap.controls.LDAPVirtualListControl; +import netscape.ldap.controls.LDAPVirtualListResponse; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.IElementProcessor; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents a virtual list of search results. + * Note that this class must be used with DS4.0. + * + * @author thomask + * @author mzhao + * @version $Revision$, $Date$ + */ +public class DBVirtualList<E> implements IDBVirtualList<E> { + + private IDBRegistry mRegistry = null; + private LDAPConnection mConn = null; + private String mBase = null; + private String mFilter = null; + private String mAttrs[] = null; + // virtual list size + private int mSize = -1; + + private Vector<E> mEntries = new Vector<E>(); + // mSize is get or not? + private boolean mInitialized = false; + private LDAPSortKey[] mKeys; + private LDAPControl[] mPageControls = null; + // page buffer size + private int mPageSize = 10; + // the top of the buffer + private int mTop = 0; + private int mBeforeCount; + private int mAfterCount; + // the index of the first entry returned + private int mSelectedIndex = 0; + private int mJumpToIndex = 0; + private int mJumpToInitialIndex = 0; // Initial index hit in jumpto operation + private int mJumpToDirection = 1; // Do we proceed forward or backwards + private String mJumpTo = null; // Determines if this is the jumpto case + + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs a virtual list. + * Be sure to setPageSize() later if your pageSize is not the default 10 + * Be sure to setSortKey() before fetchs + * + * param registry the registry of attribute mappers + * param c the ldap connection. It has to be version 3 and upper + * param base the base distinguished name to search from + * param filter search filter specifying the search criteria + * param attrs list of attributes that you want returned in the search results + */ + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[]) throws EBaseException { + mRegistry = registry; + mFilter = filter; + mBase = base; + mAttrs = attrs; + CMS.debug("In DBVirtualList filter attrs filter: " + filter + + " attrs: " + Arrays.toString(attrs)); + mPageControls = new LDAPControl[2]; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + } + + /** + * Constructs a virtual list. + * Be sure to setPageSize() later if your pageSize is not the default 10 + * + * param registry the registry of attribute mappers + * param c the ldap connection. It has to be version 3 and upper + * param base the base distinguished name to search from + * param filter search filter specifying the search criteria + * param attrs list of attributes that you want returned in the search results + * param sortKey the attributes to sort by + */ + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[], String sortKey[]) + throws EBaseException { + + CMS.debug("In DBVirtualList filter attrs sotrKey[] filter: " + filter + + " attrs: " + Arrays.toString(attrs)); + mRegistry = registry; + mFilter = filter; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + mBase = base; + mAttrs = attrs; + mPageControls = new LDAPControl[2]; + setSortKey(sortKey); + } + + /** + * Constructs a virtual list. + * Be sure to setPageSize() later if your pageSize is not the default 10 + * + * param registry the registry of attribute mappers + * param c the ldap connection. It has to be version 3 and upper + * param base the base distinguished name to search from + * param filter search filter specifying the search criteria + * param attrs list of attributes that you want returned in the search results + * param sortKey the attribute to sort by + */ + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[], String sortKey) + throws EBaseException { + + CMS.debug("In DBVirtualList filter attrs sortKey filter: " + filter + " attrs: " + Arrays.toString(attrs)); + mRegistry = registry; + mFilter = filter; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + mBase = base; + mAttrs = attrs; + mPageControls = new LDAPControl[2]; + setSortKey(sortKey); + } + + /** + * Constructs a virtual list. + * + * param registry the registry of attribute mappers + * param c the ldap connection. It has to be version 3 and upper + * param base the base distinguished name to search from + * param filter search filter specifying the search criteria + * param attrs list of attributes that you want returned in the search results + * param sortKey the attributes to sort by + * param pageSize the size of a page. There is a 3*pageSize buffer maintained so + * pageUp and pageDown won't invoke fetch from ldap server + */ + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[], String sortKey[], + int pageSize) throws EBaseException { + + CMS.debug("In DBVirtualList filter attrs sortKey[] pageSize filter: " + + filter + " attrs: " + Arrays.toString(attrs) + + " pageSize " + pageSize); + mRegistry = registry; + mFilter = filter; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + mBase = base; + mAttrs = attrs; + mPageControls = new LDAPControl[2]; + setSortKey(sortKey); + setPageSize(pageSize); + } + + /** + * Constructs a virtual list. + * + * param registry the registry of attribute mappers + * param c the ldap connection. It has to be version 3 and upper + * param base the base distinguished name to search from + * param filter search filter specifying the search criteria + * param attrs list of attributes that you want returned in the search results + * param sortKey the attribute to sort by + * param pageSize the size of a page. There is a 3*pageSize buffer maintained so + * pageUp and pageDown won't invoke fetch from ldap server + */ + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[], String sortKey, + int pageSize) throws EBaseException { + + CMS.debug("In DBVirtualList filter attrs sortKey pageSize filter: " + + filter + " attrs: " + Arrays.toString(attrs) + + " pageSize " + pageSize); + mRegistry = registry; + mFilter = filter; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + mBase = base; + mAttrs = attrs; + mPageControls = new LDAPControl[2]; + setSortKey(sortKey); + setPageSize(pageSize); + } + + public DBVirtualList(IDBRegistry registry, LDAPConnection c, + String base, String filter, String attrs[], + String startFrom, String sortKey, + int pageSize) throws EBaseException { + + CMS.debug("In DBVirtualList filter attrs startFrom sortKey pageSize " + + "filter: " + filter + + " attrs: " + Arrays.toString(attrs) + + " pageSize " + pageSize + " startFrom " + startFrom); + mRegistry = registry; + mFilter = filter; + try { + mConn = (LDAPConnection) c.clone(); + } catch (Exception e) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_CONN_FAILED", + e.toString())); + } + mBase = base; + mAttrs = attrs; + mPageControls = new LDAPControl[2]; + mJumpTo = startFrom; + setSortKey(sortKey); + // setPageSize(pageSize); + + if (pageSize < 0) { + mJumpToDirection = -1; + } + mPageSize = pageSize; + + mBeforeCount = 0; + mAfterCount = mPageSize; + } + + /** + * Set the paging size of this virtual list. + * The page size here is just a buffer size. A buffer is kept around + * that is three times as large as the number of visible entries. + * That way, you can scroll up/down several items(up to a page-full) + * without refetching entries from the directory. + * + * @param size the page size + */ + public void setPageSize(int size) { + + if (mJumpTo != null) { + return; + } + + mPageSize = size; + mBeforeCount = 0; //mPageSize; + mAfterCount = mPageSize; // mPageSize + mPageSize; + + //CMS.debug("In setPageSize " + size + " mBeforeCount " + mBeforeCount + " mAfterCount " + mAfterCount); + } + + /** + * set the sort key + * + * @param sortKey the attribute to sort by + */ + public void setSortKey(String sortKey) throws EBaseException { + String keys[] = new String[1]; + + keys[0] = sortKey; + setSortKey(keys); + } + + /** + * set the sort key + * + * @param sortKey the attributes to sort by + */ + public void setSortKey(String[] sortKeys) throws EBaseException { + if (sortKeys == null) + throw new EBaseException("sort keys cannot be null"); + try { + + mKeys = new LDAPSortKey[sortKeys.length]; + String la[] = mRegistry.getLDAPAttributes(sortKeys); + + for (int j = 0; j < sortKeys.length; j++) { + mKeys[j] = new LDAPSortKey(la[j]); + } + } catch (Exception e) { + + /*LogDoc + * + * @phase local ldap search + * @reason Failed at setSortKey. + * @message DBVirtualList: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + // Paged results also require a sort control + if (mKeys != null) { + mPageControls[0] = + new LDAPSortControl(mKeys, true); + } else { + throw new EBaseException("sort keys cannot be null"); + } + } + + /** + * Retrieves the size of this virtual list. + * Recommend to call getSize() before getElementAt() or getElements() + * since you'd better check if the index is out of bound first. + */ + public int getSize() { + if (!mInitialized) { + mInitialized = true; + // Do an initial search to get the virtual list size + // Keep one page before and one page after the start + if (mJumpTo == null) { + mBeforeCount = 0; //mPageSize; + mAfterCount = mPageSize; // mPageSize + mPageSize; + } + // Create the initial paged results control + /* Since this one is only used to get the size of the virtual list; + we don't care about the starting index. If there is no partial + match, the first one before (or after, if none before) is returned + as the index entry. Instead of "A", you could use the other + constructor and specify 0 both for startIndex and for + contentCount. */ + LDAPVirtualListControl cont = null; + + if (mJumpTo == null) { + cont = new LDAPVirtualListControl("A", + mBeforeCount, + mAfterCount); + } else { + + if (mPageSize < 0) { + mBeforeCount = mPageSize * -1; + mAfterCount = 0; + } + cont = new LDAPVirtualListControl(mJumpTo, + mBeforeCount, + mAfterCount); + } + mPageControls[1] = cont; + getJumpToPage(); + } + + CMS.debug("Getting Virtual List size: " + mSize); + return mSize; + } + + public int getSizeBeforeJumpTo() { + + if (!mInitialized || mJumpTo == null) + return 0; + + int size = 0; + + if (mJumpToDirection < 0) { + size = mTop + mEntries.size(); + } else { + size = mTop; + + } + + return size; + + } + + public int getSizeAfterJumpTo() { + + if (!mInitialized || mJumpTo == null) + return 0; + + int size = mSize - mTop; + + return size; + + } + + private synchronized boolean getEntries() { + // Specify necessary controls for vlist + // LDAPSearchConstraints cons = mConn.getSearchConstraints(); + LDAPSearchConstraints cons = new LDAPSearchConstraints(); + + cons.setMaxResults(0); + if (mPageControls != null) { + cons.setServerControls(mPageControls); + //System.out.println( "setting vlist control" ); + } + // Empty the buffer + mEntries.removeAllElements(); + // Do a search + try { + //what happen if there is no matching? + String ldapFilter = mRegistry.getFilter(mFilter); + String ldapAttrs[] = null; + LDAPSearchResults result; + + if (mAttrs != null) { + ldapAttrs = mRegistry.getLDAPAttributes(mAttrs); + + /* + LDAPv2.SCOPE_BASE: + (search only the base DN) + LDAPv2.SCOPE_ONE: + (search only entries under the base DN) + LDAPv2.SCOPE_SUB: + (search the base DN and all entries within its subtree) + */ + result = mConn.search(mBase, + LDAPConnection.SCOPE_ONE, ldapFilter, ldapAttrs, + false, cons); + + } else { + result = mConn.search(mBase, + LDAPConnection.SCOPE_ONE, ldapFilter, null, + false, cons); + } + if (result == null) { + return false; + } + int damageCounter = 0; + + while (result.hasMoreElements()) { + LDAPEntry entry = (LDAPEntry) result.nextElement(); + + try { + //maintain mEntries as vector of LDAPEntry + @SuppressWarnings("unchecked") + E o = (E) mRegistry.createObject(entry.getAttributeSet()); + + mEntries.addElement(o); + } catch (Exception e) { + + CMS.debug("Exception " + e); + + /*LogDoc + * + * @phase local ldap search + * @reason Failed to get enties. + * @message DBVirtualList: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_VL_ADD", e.toString())); + // #539044 + damageCounter++; + if (damageCounter > 100) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_VL_CORRUPTED_ENTRIES", Integer.toString(damageCounter))); + return false; + } + } + } + } catch (Exception e) { + + /*LogDoc + * + * @phase local ldap search + * @reason Failed to get enties. + * @message DBVirtualList: <exception thrown> + */ + CMS.debug("getEntries: exception " + e); + + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + //System.out.println( "Returning " + mEntries.size() + + // " entries" ); + + CMS.debug("getEntries returning " + mEntries.size()); + return true; + } + + public int getCurrentIndex() { + return mTop; + } + + private synchronized boolean getJumpToPage() { + try { + // Get the actual entries + if (!getEntries()) + return false; + + // Check if we have a control returned + LDAPControl[] c = mConn.getResponseControls(); + LDAPVirtualListResponse nextCont = + LDAPVirtualListResponse.parseResponse(c); + + if (nextCont != null) { + mSelectedIndex = nextCont.getFirstPosition() - 1; + mTop = Math.max(0, mSelectedIndex - mBeforeCount); + + CMS.debug("mTop " + mTop); + if (mJumpTo != null) { + mJumpToInitialIndex = mTop; + } + + // Now we know the total size of the virtual list box + mSize = nextCont.getContentCount(); + ((LDAPVirtualListControl) mPageControls[1]).setListSize(mSize); + mInitialized = true; + //System.out.println( "Virtual window: " + mTop + + // ".." + (mTop+mEntries.size()-1) + + // " of " + mSize ); + } else { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_VL_NULL_RESPONSE")); + } + return true; + } catch (Exception e) { + // happens when connection is not available + return false; + } + } + + /** + * Get a page starting at "first" (although we may also fetch + * some preceding entries) + * Recommend to call getSize() before getElementAt() or getElements() + * since you'd better check if the index is out of bound first. + * + * @param first the index of the first entry of the page you want to fetch + */ + public boolean getPage(int first) { + CMS.debug("getPage " + first); + if (!mInitialized) { + LDAPVirtualListControl cont = new LDAPVirtualListControl(0, + mBeforeCount, + mAfterCount, 0); + + mPageControls[1] = cont; + } + + //CMS.debug("about to set range first " + first + " mBeforeCount " + mBeforeCount + " mAfterCount " + mAfterCount); + ((LDAPVirtualListControl) mPageControls[1]).setRange(first, mBeforeCount, mAfterCount); + return getPage(); + } + + /** + * Fetch a buffer + */ + private boolean getPage() { + // Get the actual entries + if (!getEntries()) + return false; + + // Check if we have a control returned + LDAPControl[] c = mConn.getResponseControls(); + LDAPVirtualListResponse nextCont = + LDAPVirtualListResponse.parseResponse(c); + + if (nextCont != null) { + mSelectedIndex = nextCont.getFirstPosition() - 1; + mTop = Math.max(0, mSelectedIndex - mBeforeCount); + //CMS.debug("New mTop: " + mTop + " mSelectedIndex " + mSelectedIndex); + // Now we know the total size of the virtual list box + mSize = nextCont.getContentCount(); + ((LDAPVirtualListControl) mPageControls[1]).setListSize(mSize); + mInitialized = true; + //System.out.println( "Virtual window: " + mTop + + // ".." + (mTop+mEntries.size()-1) + + // " of " + mSize ); + } else { + + /*LogDoc + * + * @phase local ldap search + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_VL_NULL_RESPONSE")); + } + return true; + } + + /** + * Called by application to scroll the list with initial letters. + * Consider text to be an initial substring of the attribute of the + * primary sorting key(the first one specified in the sort key array) + * of an entry. + * If no entries match, the one just before(or after, if none before) + * will be returned as mSelectedIndex + * + * @param text the prefix of the first entry of the page you want to fetch + */ + public boolean getPage(String text) { + mPageControls[1] = + new LDAPVirtualListControl(text, + mBeforeCount, + mAfterCount); + //System.out.println( "Setting requested start to " + + // text + ", -" + mBeforeCount + ", +" + + // mAfterCount ); + return getPage(); + } + + /** + * fetch data of a single list item + * Recommend to call getSize() before getElementAt() or getElements() + * since you'd better check if the index is out of bound first. + * If the index is out of range of the virtual list, an exception will be thrown + * and return null + * + * @param index the index of the element to fetch + */ + public E getElementAt(int index) { + + /* mSize may not be init at this time! Bad ! + * the caller should really check the index is within bound before this + * but I'll take care of this just in case they are too irresponsible + */ + if (!mInitialized) + mSize = getSize(); + + CMS.debug("getElementAt: " + index + " mTop " + mTop); + + //System.out.println( "need entry " + index ); + if ((index < 0) || (index >= mSize)) { + CMS.debug("returning null"); + return null; + } + + if (mJumpTo != null) { //Handle the explicit jumpto case + + if (index == 0) + mJumpToIndex = 0; // Keep a running jumpto index for this page of data + else + mJumpToIndex++; + + //CMS.debug("getElementAtJT: " + index + " mTop " + mTop + " mEntries.size() " + mEntries.size()); + + if ((mJumpToDirection > 0) && (mJumpToInitialIndex + index >= mSize)) // out of data in forward paging jumpto case + { + CMS.debug("mJumpTo virtual list exhausted mTop " + mTop + " mSize " + mSize); + return null; + } + + if (mJumpToIndex >= mEntries.size()) // In jumpto case, page of data has been exhausted + { + mJumpToIndex = 0; // new page will be needed reset running count + + if (mJumpToDirection > 0) { //proceed in positive direction past hit point + getPage(index + mJumpToInitialIndex + 1); + } else { //proceed backwards from hit point + if (mTop == 0) { + getPage(0); + CMS.debug("asking for a page less than zero in reverse case, return null"); + return null; + } + + CMS.debug("getting page reverse mJumptoIndex " + mJumpToIndex + " mTop " + mTop); + getPage(mTop); + + } + + } + + if (mJumpToDirection > 0) // handle getting entry in forward direction + { + return mEntries.elementAt(mJumpToIndex); + } else { // handle getting entry in reverse direction + int reverse_index = mEntries.size() - mJumpToIndex - 1; + + CMS.debug("reverse direction getting index " + reverse_index); + + if (reverse_index < 0 || reverse_index >= mEntries.size()) { + CMS.debug("reverse_index out of range " + reverse_index); + return null; + } + return mEntries.elementAt(reverse_index); + } + } + + //CMS.debug("getElementAt noJumpto: " + index); + + if ((index < mTop) || (index >= mTop + mEntries.size())) { // handle the non jumpto case + //fetch a new page + //System.out.println( "fetching a page starting at " + + // index ); + // CMS.debug("getElementAt noJumpto: getting page index: " + index + " mEntries.size() " + mEntries.size() + " mTop: " + mTop); + getPage(index); + } + + int offset = index - mTop; + + if ((offset < 0) || (offset >= mEntries.size())) + //XXX + return null; //("No entry at " + index); + else + return mEntries.elementAt(offset); + } + + public E getJumpToElementAt(int i) { + return mEntries.elementAt(i); + } + + /** + * This function processes elements as soon as it arrives. It is + * more memory-efficient. + */ + public void processElements(int startidx, int endidx, IElementProcessor ep) + throws EBaseException { + + /* mSize may not be init at this time! Bad ! + * the caller should really check the index is within bound before this + * but I'll take care of this just in case they are too irresponsible + */ + if (!mInitialized) + mSize = getSize(); + + // short-cut the existing code ... :( + if (mJumpTo != null) { + for (int i = startidx; i <= endidx; i++) { + Object element = getJumpToElementAt(i); + + if (element != null) + ep.process(element); + } + return; + } + + //guess this is what you really mean to try to improve performance + if (startidx >= endidx) { + throw new EBaseException("startidx must be less than endidx"); + } else { + setPageSize(endidx - startidx); + getPage(startidx); + } + + for (int i = startidx; i <= endidx; i++) { + Object element = getElementAt(i); + + if (element != null) + ep.process(element); + } + } + + /** + * get the virutal selected index + */ + public int getSelectedIndex() { + return mSelectedIndex; + } + + /** + * get the top of the buffer + */ + public int getFirstIndex() { + return mTop; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DateArrayMapper.java b/base/common/src/com/netscape/cmscore/dbs/DateArrayMapper.java new file mode 100644 index 000000000..20562404b --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DateArrayMapper.java @@ -0,0 +1,109 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java Date array object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DateArrayMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs a date array mapper. + */ + public DateArrayMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of support ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to a set of attributes. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + Date dates[] = (Date[]) obj; + + if (dates == null) + return; + LDAPAttribute attr = new LDAPAttribute(mLdapName); + + for (int i = 0; i < dates.length; i++) { + attr.addValue(DateMapper.dateToDB(dates[i])); + } + attrs.add(attr); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + @SuppressWarnings("unchecked") + Enumeration<String> e = attr.getStringValues(); + Vector<Date> v = new Vector<Date>(); + + while (e.hasMoreElements()) { + v.addElement(DateMapper.dateFromDB(e.nextElement())); + } + if (v.size() == 0) + return; + Date dates[] = new Date[v.size()]; + + v.copyInto(dates); + parent.set(name, dates); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/DateMapper.java b/base/common/src/com/netscape/cmscore/dbs/DateMapper.java new file mode 100644 index 000000000..a767758f6 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/DateMapper.java @@ -0,0 +1,113 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java Date object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class DateMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + private static SimpleDateFormat formatter = new + SimpleDateFormat("yyyyMMddHHmmss'Z'"); + + /** + * Constructs date mapper. + */ + public DateMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + dateToDB((Date) obj))); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + parent.set(name, dateFromDB((String) + attr.getStringValues().nextElement())); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + String val = null; + + try { + val = dateToDB(new Date(Long.parseLong(value))); + } catch (NumberFormatException e) { + val = value; + } + return mLdapName + op + val; + } + + public synchronized static String dateToDB(Date date) { + return formatter.format(date); + } + + public synchronized static Date dateFromDB(String dbDate) { + try { + return formatter.parse(dbDate); + } catch (ParseException e) { + } + return null; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/IntegerMapper.java b/base/common/src/com/netscape/cmscore/dbs/IntegerMapper.java new file mode 100644 index 000000000..8dc07e4d9 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/IntegerMapper.java @@ -0,0 +1,89 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java Integer object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class IntegerMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs mapper to deal with Integer. + */ + public IntegerMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of supported ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + ((Integer) obj).toString())); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + parent.set(name, new Integer((String) + attr.getStringValues().nextElement())); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java b/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java new file mode 100644 index 000000000..50b3badc3 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyDBSchema.java @@ -0,0 +1,51 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +/** + * A class represents a collection of key record + * specific schema information. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyDBSchema { + + public static final String LDAP_OC_TOP = "top"; + public static final String LDAP_ATTR_SERIALNO = "serialno"; + public static final String LDAP_ATTR_CREATE_TIME = "dateOfCreate"; + public static final String LDAP_ATTR_MODIFY_TIME = "dateOfModify"; + public static final String LDAP_ATTR_META_INFO = "metaInfo"; + public static final String LDAP_OC_KEYRECORD = "keyRecord"; + public static final String LDAP_ATTR_OWNER_NAME = "ownerName"; + public static final String LDAP_ATTR_PRIVATE_KEY_DATA = "privateKeyData"; + public static final String LDAP_ATTR_KEY_RECORD_ID = "keyRecordId"; + public static final String LDAP_ATTR_PUBLIC_KEY_DATA = "publicKeyData"; + public static final String LDAP_ATTR_KEY_SIZE = "keySize"; + public static final String LDAP_ATTR_ALGORITHM = "algorithm"; + public static final String LDAP_ATTR_STATE = "keyState"; + public static final String LDAP_ATTR_DATE_OF_RECOVERY = + "dateOfRecovery"; + public static final String LDAP_ATTR_PUBLIC_KEY_FORMAT = + "publicKeyFormat"; + public static final String LDAP_ATTR_ARCHIVED_BY = "archivedBy"; + public static final String LDAP_ATTR_CLIENT_ID = "clientId"; + public static final String LDAP_ATTR_STATUS = "status"; + public static final String LDAP_ATTR_DATA_TYPE = "dataType"; +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java b/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java new file mode 100644 index 000000000..f7773e3fa --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyRecord.java @@ -0,0 +1,386 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.KeyState; + +/** + * A class represents a Key record. It maintains the key + * life cycle as well as other information about an + * archived key. Namely, whether a key is inactive because + * of compromise. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyRecord implements IDBObj, IKeyRecord { + + /** + * + */ + private static final long serialVersionUID = -3765000841161998984L; + private BigInteger mSerialNo = null; + private KeyState mState = null; + private MetaInfo mMetaInfo = null; + private String mAlgorithm = null; + private byte mPrivateKey[] = null; + private byte mPublicKey[] = null; + private Integer mSize = null; + private String mOwnerName = null; + private Date mDatesOfRecovery[] = null; + private Date mCreateTime = null; + private Date mModifyTime = null; + private String mArchivedBy = null; + private String mClientId = null; + private String mStatus = null; + private String mDataType = null; + + + protected static Vector<String> mNames = new Vector<String>(); + static { + mNames.addElement(ATTR_STATE); + mNames.addElement(ATTR_ID); + mNames.addElement(ATTR_OWNER_NAME); + mNames.addElement(ATTR_KEY_SIZE); + mNames.addElement(ATTR_ALGORITHM); + mNames.addElement(ATTR_PRIVATE_KEY_DATA); + mNames.addElement(ATTR_PUBLIC_KEY_DATA); + mNames.addElement(ATTR_DATE_OF_RECOVERY); + mNames.addElement(ATTR_META_INFO); + mNames.addElement(ATTR_CREATE_TIME); + mNames.addElement(ATTR_MODIFY_TIME); + mNames.addElement(ATTR_ARCHIVED_BY); + mNames.addElement(ATTR_CLIENT_ID); + mNames.addElement(ATTR_STATUS); + mNames.addElement(ATTR_DATA_TYPE); + } + + /** + * Constructs empty key record. + */ + public KeyRecord() { + } + + /* + * Constructs key record. + * + * @param key key to be archived + */ + public KeyRecord(BigInteger serialNo, byte publicData[], + byte privateData[], String owner, + String algorithm, String agentId) + throws EBaseException { + mSerialNo = serialNo; + mPublicKey = publicData; + mPrivateKey = privateData; + mOwnerName = owner; + mAlgorithm = algorithm; + mState = KeyState.VALID; + mCreateTime = com.netscape.certsrv.apps.CMS.getCurrentDate(); + mModifyTime = com.netscape.certsrv.apps.CMS.getCurrentDate(); + mArchivedBy = agentId; + } + + /** + * Sets an attribute. + * <P> + */ + public void set(String name, Object object) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_STATE)) { + mState = (KeyState) object; + } else if (name.equalsIgnoreCase(ATTR_ID)) { + mSerialNo = (BigInteger) object; + } else if (name.equalsIgnoreCase(ATTR_KEY_SIZE)) { + mSize = (Integer) object; + } else if (name.equalsIgnoreCase(ATTR_OWNER_NAME)) { + mOwnerName = (String) object; + } else if (name.equalsIgnoreCase(ATTR_ALGORITHM)) { + mAlgorithm = (String) object; + } else if (name.equalsIgnoreCase(ATTR_PRIVATE_KEY_DATA)) { + mPrivateKey = (byte[]) object; + } else if (name.equalsIgnoreCase(ATTR_PUBLIC_KEY_DATA)) { + mPublicKey = (byte[]) object; + } else if (name.equalsIgnoreCase(ATTR_DATE_OF_RECOVERY)) { + mDatesOfRecovery = (Date[]) object; + } else if (name.equalsIgnoreCase(ATTR_META_INFO)) { + mMetaInfo = (MetaInfo) object; + } else if (name.equalsIgnoreCase(ATTR_CREATE_TIME)) { + mCreateTime = (Date) object; + } else if (name.equalsIgnoreCase(ATTR_MODIFY_TIME)) { + mModifyTime = (Date) object; + } else if (name.equalsIgnoreCase(ATTR_ARCHIVED_BY)) { + mArchivedBy = (String) object; + } else if (name.equalsIgnoreCase(ATTR_CLIENT_ID)) { + mClientId = (String) object; + } else if (name.equalsIgnoreCase(ATTR_DATA_TYPE)) { + mDataType = (String) object; + } else if (name.equalsIgnoreCase(ATTR_STATUS)) { + mStatus = (String) object; + } else { + throw new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Retrieves an attribute. + * <P> + */ + public Object get(String name) throws EBaseException { + if (name.equalsIgnoreCase(ATTR_STATE)) { + return mState; + } else if (name.equalsIgnoreCase(ATTR_ID)) { + return mSerialNo; + } else if (name.equalsIgnoreCase(ATTR_KEY_SIZE)) { + return mSize; + } else if (name.equalsIgnoreCase(ATTR_OWNER_NAME)) { + return mOwnerName; + } else if (name.equalsIgnoreCase(ATTR_ALGORITHM)) { + return mAlgorithm; + } else if (name.equalsIgnoreCase(ATTR_PRIVATE_KEY_DATA)) { + return mPrivateKey; + } else if (name.equalsIgnoreCase(ATTR_PUBLIC_KEY_DATA)) { + return mPublicKey; + } else if (name.equalsIgnoreCase(ATTR_DATE_OF_RECOVERY)) { + return mDatesOfRecovery; + } else if (name.equalsIgnoreCase(ATTR_CREATE_TIME)) { + return mCreateTime; + } else if (name.equalsIgnoreCase(ATTR_MODIFY_TIME)) { + return mModifyTime; + } else if (name.equalsIgnoreCase(ATTR_META_INFO)) { + return mMetaInfo; + } else if (name.equalsIgnoreCase(ATTR_ARCHIVED_BY)) { + return mArchivedBy; + } else if (name.equalsIgnoreCase(ATTR_CLIENT_ID)) { + return mClientId; + } else if (name.equalsIgnoreCase(ATTR_DATA_TYPE)) { + return mDataType; + } else if (name.equalsIgnoreCase(ATTR_STATUS)) { + return mStatus; + } else { + throw new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Deletes an attribute. + * <P> + */ + public void delete(String name) throws EBaseException { + throw new EBaseException(com.netscape.certsrv.apps.CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + + /** + * Retrieves an enumeration of attributes. + * <P> + */ + public Enumeration<String> getElements() { + return mNames.elements(); + } + + /** + * Retrieves serializable attribute names. + */ + public Enumeration<String> getSerializableAttrNames() { + return mNames.elements(); + } + + /** + * Retrieves serial number of the key record. Each key record + * is uniquely identified by serial number. + * <P> + * + * @return serial number of this key record + */ + public BigInteger getSerialNumber() throws EBaseException { + return mSerialNo; + } + + /** + * Sets serial number. + */ + public void setSerialNumber(BigInteger serialno) throws EBaseException { + mSerialNo = serialno; + } + + /** + * Retrieves the key state. This gives key life cycle + * information. + * <P> + * + * @return key state + */ + public KeyState getState() throws EBaseException { + return mState; + } + + /** + * Sets key state. + * <P> + */ + public void setState(KeyState state) throws EBaseException { + mState = state; + } + + /** + * Retrieves the uid of person who archived this record. + */ + public String getArchivedBy() { + return mArchivedBy; + } + + /** + * Retrieves key. + * <P> + * + * @return archived key + */ + public byte[] getPrivateKeyData() throws EBaseException { + return mPrivateKey; + } + + /** + * Sets key data. + */ + public void setPrivateKeyData(byte keydata[]) throws EBaseException { + mPrivateKey = keydata; + } + + /** + * Retrieves the key size. + * <P> + * + * @return key size + */ + public Integer getKeySize() throws EBaseException { + return mSize; + } + + /** + * Sets key size. + * <P> + */ + public void setKeySize(Integer keySize) throws EBaseException { + mSize = keySize; + } + + /** + * Retrieves owner name. + * <P> + */ + public String getOwnerName() throws EBaseException { + return mOwnerName; + } + + /** + * Sets owner name. + * <P> + */ + public void setOwnerName(String name) throws EBaseException { + mOwnerName = name; + } + + /** + * Retrieves the public key. + * <P> + */ + public byte[] getPublicKeyData() throws EBaseException { + return mPublicKey; + } + + /** + * Sets the public key. + * <P> + */ + public void setPublicKeyData(byte key[]) throws EBaseException { + mPublicKey = key; + } + + /** + * Retrieves the date(s) of revocation. + * <P> + */ + public Date[] getDateOfRevocation() throws EBaseException { + return mDatesOfRecovery; + } + + /** + * Sets the dateso of revocation. + * <P> + */ + public void setDateOfRevocation(Date dates[]) throws EBaseException { + mDatesOfRecovery = dates; + } + + /** + * Retrieves algorithm of the key pair. + */ + public String getAlgorithm() { + return mAlgorithm; + } + + public MetaInfo getMetaInfo() { + return mMetaInfo; + } + + /** + * Retrieves the creation time of this record. + */ + public Date getCreateTime() { + return mCreateTime; + } + + /** + * Retrieves the last modification time of + * this record. + */ + public Date getModifyTime() { + return mModifyTime; + } + + /** + * Retrieves the client ID of this record. + */ + public String getClientId() throws EBaseException { + return mClientId ; + } + + /** + * Retrieves the key status of this record. + */ + public String getKeyStatus() throws EBaseException { + return mStatus; + + } + + /** + * Retrieves the key data type of this record. + */ + public String getDataType() throws EBaseException { + return mDataType; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyRecordList.java b/base/common/src/com/netscape/cmscore/dbs/KeyRecordList.java new file mode 100644 index 000000000..941b0552d --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyRecordList.java @@ -0,0 +1,89 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBVirtualList; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRecordList; + +/** + * A class represents a list of key records. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyRecordList implements IKeyRecordList { + + private IDBVirtualList<IKeyRecord> mVlist = null; + + /** + * Constructs a key list. + */ + public KeyRecordList(IDBVirtualList<IKeyRecord> vlist) { + mVlist = vlist; + } + + /** + * Retrieves the size of key list. + */ + public int getSize() { + return mVlist.getSize(); + } + + public int getSizeBeforeJumpTo() { + + return mVlist.getSizeBeforeJumpTo(); + + } + + public int getSizeAfterJumpTo() { + + return mVlist.getSizeAfterJumpTo(); + } + + public IKeyRecord getKeyRecord(int i) { + IKeyRecord record = mVlist.getElementAt(i); + + if (record == null) + return null; + + return record; + } + + /** + * Retrieves requests. + */ + public Enumeration<IKeyRecord> getKeyRecords(int startidx, int endidx) + throws EBaseException { + Vector<IKeyRecord> entries = new Vector<IKeyRecord>(); + + for (int i = startidx; i <= endidx; i++) { + IKeyRecord element = mVlist.getElementAt(i); + + if (element != null) { + entries.addElement(element); + } + } + return entries.elements(); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyRecordMapper.java b/base/common/src/com/netscape/cmscore/dbs/KeyRecordMapper.java new file mode 100644 index 000000000..1a6103492 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyRecordMapper.java @@ -0,0 +1,112 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents a mapper to serialize + * key record into database. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyRecordMapper implements IDBAttrMapper { + + private IKeyRepository mDB = null; + private ILogger mLogger = CMS.getLogger(); + + public KeyRecordMapper(IKeyRepository db) { + mDB = db; + } + + public Enumeration<String> getSupportedLDAPAttributeNames() { + Vector<String> v = new Vector<String>(); + + v.addElement(KeyDBSchema.LDAP_ATTR_KEY_RECORD_ID); + return v.elements(); + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) throws EBaseException { + try { + KeyRecord rec = (KeyRecord) obj; + + attrs.add(new LDAPAttribute(KeyDBSchema.LDAP_ATTR_KEY_RECORD_ID, + rec.getSerialNumber().toString())); + } catch (Exception e) { + + /*LogDoc + * + * @phase Maps object to ldap attribute set + * @message KeyRecordMapper: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_KEYRECORD_MAPPER_ERROR", e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_SERIALIZE_FAILED", name)); + } + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + try { + LDAPAttribute attr = attrs.getAttribute( + KeyDBSchema.LDAP_ATTR_KEY_RECORD_ID); + + if (attr == null) + return; + String serialno = (String) attr.getStringValues().nextElement(); + IKeyRecord rec = mDB.readKeyRecord(new + BigInteger(serialno)); + + parent.set(name, rec); + } catch (Exception e) { + + /*LogDoc + * + * @phase Maps ldap attribute set to object + * @message KeyRecordMapper: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_KEYRECORD_MAPPER_ERROR", e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } + } + + public String mapSearchFilter(String name, String op, String value) + throws EBaseException { + return name + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java b/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java new file mode 100644 index 000000000..3b2186b23 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyRepository.java @@ -0,0 +1,586 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.security.x509.X500Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBRegistry; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSearchResults; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.keydb.IKeyRecord; +import com.netscape.certsrv.dbs.keydb.IKeyRecordList; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.dbs.repository.IRepository; + +/** + * A class represents a Key repository. This is the container of + * archived keys. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyRepository extends Repository implements IKeyRepository { + + public KeyStatusUpdateThread mKeyStatusUpdateThread = null; + protected IDBSubsystem mDBService = null; + + /** + * Internal constants + */ + private String mBaseDN = null; + + /** + * Constructs a key repository. It checks if the key repository + * does exist. If not, it creates the repository. + * <P> + * + * @param service db service + * @exception EBaseException failed to setup key repository + */ + public KeyRepository(IDBSubsystem service, int increment, String baseDN) + throws EDBException { + super(service, increment, baseDN); + mBaseDN = baseDN; + mDBService = service; + + // register key record schema + IDBRegistry reg = service.getRegistry(); + String keyRecordOC[] = new String[2]; + + keyRecordOC[0] = KeyDBSchema.LDAP_OC_TOP; + keyRecordOC[1] = KeyDBSchema.LDAP_OC_KEYRECORD; + + if (!reg.isObjectClassRegistered(KeyRecord.class.getName())) { + reg.registerObjectClass(KeyRecord.class.getName(), + keyRecordOC); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ID)) { + reg.registerAttribute(KeyRecord.ATTR_ID, new + BigIntegerMapper(KeyDBSchema.LDAP_ATTR_SERIALNO)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ALGORITHM)) { + reg.registerAttribute(KeyRecord.ATTR_ALGORITHM, new + StringMapper(KeyDBSchema.LDAP_ATTR_ALGORITHM)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_STATE)) { + reg.registerAttribute(KeyRecord.ATTR_STATE, new + KeyStateMapper(KeyDBSchema.LDAP_ATTR_STATE)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_KEY_SIZE)) { + reg.registerAttribute(KeyRecord.ATTR_KEY_SIZE, new + IntegerMapper(KeyDBSchema.LDAP_ATTR_KEY_SIZE)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_OWNER_NAME)) { + reg.registerAttribute(KeyRecord.ATTR_OWNER_NAME, new + StringMapper(KeyDBSchema.LDAP_ATTR_OWNER_NAME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_PRIVATE_KEY_DATA)) { + reg.registerAttribute(KeyRecord.ATTR_PRIVATE_KEY_DATA, new + ByteArrayMapper(KeyDBSchema.LDAP_ATTR_PRIVATE_KEY_DATA)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_PUBLIC_KEY_DATA)) { + reg.registerAttribute(KeyRecord.ATTR_PUBLIC_KEY_DATA, new + PublicKeyMapper(KeyDBSchema.LDAP_ATTR_PUBLIC_KEY_DATA)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_DATE_OF_RECOVERY)) { + reg.registerAttribute(KeyRecord.ATTR_DATE_OF_RECOVERY, new + DateArrayMapper(KeyDBSchema.LDAP_ATTR_DATE_OF_RECOVERY)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_CREATE_TIME)) { + reg.registerAttribute(KeyRecord.ATTR_CREATE_TIME, new + DateMapper(KeyDBSchema.LDAP_ATTR_CREATE_TIME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_MODIFY_TIME)) { + reg.registerAttribute(KeyRecord.ATTR_MODIFY_TIME, new + DateMapper(KeyDBSchema.LDAP_ATTR_MODIFY_TIME)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_META_INFO)) { + reg.registerAttribute(KeyRecord.ATTR_META_INFO, new + MetaInfoMapper(KeyDBSchema.LDAP_ATTR_META_INFO)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_ARCHIVED_BY)) { + reg.registerAttribute(KeyRecord.ATTR_ARCHIVED_BY, new + StringMapper(KeyDBSchema.LDAP_ATTR_ARCHIVED_BY)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_CLIENT_ID)) { + reg.registerAttribute(KeyRecord.ATTR_CLIENT_ID, new + StringMapper(KeyDBSchema.LDAP_ATTR_CLIENT_ID)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_STATUS)) { + reg.registerAttribute(KeyRecord.ATTR_STATUS, new + StringMapper(KeyDBSchema.LDAP_ATTR_STATUS)); + } + if (!reg.isAttributeRegistered(KeyRecord.ATTR_DATA_TYPE)) { + reg.registerAttribute(KeyRecord.ATTR_DATA_TYPE, new + StringMapper(KeyDBSchema.LDAP_ATTR_DATA_TYPE)); + } + + } + + public void setKeyStatusUpdateInterval(IRepository requestRepo, int interval) { + CMS.debug("In setKeyStatusUpdateInterval " + interval); + // don't run the thread if serial management is disabled. + if ((interval == 0) || (!mDBService.getEnableSerialMgmt())) { + CMS.debug("In setKeyStatusUpdateInterval interval = 0" + interval); + if (mKeyStatusUpdateThread != null) { + mKeyStatusUpdateThread.stop(); + } + return; + } + + CMS.debug("In setKeyStatusUpdateInterval mKeyStatusUpdateThread " + mKeyStatusUpdateThread); + if (mKeyStatusUpdateThread == null) { + CMS.debug("In setKeyStatusUpdateInterval about to create KeyStatusUpdateThread "); + mKeyStatusUpdateThread = new KeyStatusUpdateThread(this, requestRepo, "KeyStatusUpdateThread"); + mKeyStatusUpdateThread.setInterval(interval); + mKeyStatusUpdateThread.start(); + } else { + CMS.debug("In setKeyStatusUpdateInterval it thinks the thread is up already "); + mKeyStatusUpdateThread.setInterval(interval); + // dont do anything if we have a thread running already + } + } + + public IDBSubsystem getDBSubsystem() { + return mDBService; + } + + /** + * Retrieves the DN of this repository. + */ + public String getDN() { + return mBaseDN; + } + + /** + * Removes all objects with this repository. + */ + public void removeAllObjects() throws EBaseException { + String filter = "(" + KeyRecord.ATTR_OWNER_NAME + "=*" + ")"; + IKeyRecordList list = findKeyRecordsInList(filter, + null, "serialno", 10); + int size = list.getSize(); + Enumeration<IKeyRecord> e = list.getKeyRecords(0, size - 1); + while (e.hasMoreElements()) { + IKeyRecord rec = e.nextElement(); + deleteKeyRecord(rec.getSerialNumber()); + } + } + + /** + * Archives a key to the repository. + * <P> + * + * @param record key record + * @exception EBaseException failed to archive key + */ + public void addKeyRecord(IKeyRecord record) throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + ((KeyRecord) record).getSerialNumber().toString() + "," + getDN(); + + if (s != null) + s.add(name, (KeyRecord) record); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Recovers an archived key by serial number. + * <P> + * + * @param serialNo serial number + * @return key record + * @exception EBaseException failed to recover key + */ + public IKeyRecord readKeyRecord(BigInteger serialNo) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + if (s != null) + rec = (KeyRecord) s.read(name); + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * Recovers an archived key by owner name. + * <P> + * + * @param ownerName owner name + * @return key record + * @exception EBaseException failed to recover key + */ + public IKeyRecord readKeyRecord(X500Name ownerName) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + KeyRecord keyRec = null; + + try { + if (ownerName != null) { + String filter = "(" + KeyRecord.ATTR_OWNER_NAME + "=" + + ownerName.toString() + ")"; + IDBSearchResults res = s.search(getDN(), filter); + + keyRec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return keyRec; + } + + /** + * Recovers archived key using public key. + */ + public IKeyRecord readKeyRecord(PublicKey publicKey) + throws EBaseException { + // XXX - setup binary search attributes + byte data[] = publicKey.getEncoded(); + + if (data == null) + throw new EBaseException("null data"); + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String filter = "(" + KeyRecord.ATTR_PUBLIC_KEY_DATA + "=" + + escapeBinaryData(data) + ")"; + if (s != null) { + IDBSearchResults res = s.search(getDN(), filter); + + rec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * Recovers archived key using b64 encoded cert + */ + public IKeyRecord readKeyRecord(String cert) + throws EBaseException { + + IDBSSession s = mDBService.createSession(); + KeyRecord rec = null; + + try { + String filter = "(publicKey=x509cert#\"" + cert + "\")"; + CMS.debug("filter= " + filter); + + if (s != null) { + IDBSearchResults res = s.search(getDN(), filter); + + rec = (KeyRecord) res.nextElement(); + } + } finally { + if (s != null) + s.close(); + } + return rec; + } + + /** + * Modifies key record. + */ + public void modifyKeyRecord(BigInteger serialNo, ModificationSet mods) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + mods.add(KeyRecord.ATTR_MODIFY_TIME, Modification.MOD_REPLACE, + new Date()); + if (s != null) + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + public void deleteKeyRecord(BigInteger serialNo) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + + try { + String name = "cn" + "=" + + serialNo.toString() + "," + getDN(); + + if (s != null) + s.delete(name); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Read RFC-2254 + */ + public static String escapeBinaryData(byte data[]) { + String result = ""; + + for (int i = 0; i < data.length; i++) { + result = result + "\\" + Integer.toHexString((int) data[i]); + } + return result; + } + + public Enumeration<IKeyRecord> searchKeys(String filter, int maxSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<IKeyRecord> v = new Vector<IKeyRecord>(); + + try { + IDBSearchResults sr = s.search(getDN(), filter, maxSize); + while (sr.hasMoreElements()) { + v.add((IKeyRecord) sr.nextElement()); + } + } finally { + if (s != null) + s.close(); + } + return v.elements(); + } + + public Enumeration<IKeyRecord> searchKeys(String filter, int maxSize, int timeLimit) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + Vector<IKeyRecord> v = new Vector<IKeyRecord>(); + + try { + IDBSearchResults sr = s.search(getDN(), filter, maxSize, timeLimit); + while (sr.hasMoreElements()) { + v.add((IKeyRecord) sr.nextElement()); + } + } finally { + if (s != null) + s.close(); + } + return v.elements(); + } + + /** + * Retrieves key record list. + */ + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], int pageSize) throws EBaseException { + return findKeyRecordsInList(filter, attrs, IKeyRecord.ATTR_ID, + pageSize); + } + + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + IKeyRecordList list = null; + + try { + if (s != null) { + list = new KeyRecordList( + s.<IKeyRecord>createVirtualList(getDN(), "(&(objectclass=" + + KeyRecord.class.getName() + ")" + filter + ")", + attrs, sortKey, pageSize)); + } + } finally { + if (s != null) + s.close(); + } + return list; + } + + public IKeyRecordList findKeyRecordsInList(String filter, + String attrs[], String jumpTo, String sortKey, int pageSize) + throws EBaseException { + IDBSSession s = mDBService.createSession(); + IKeyRecordList list = null; + + int len = jumpTo.length(); + + String jumpToVal = null; + + if (len > 9) { + jumpToVal = Integer.toString(len) + jumpTo; + } else { + jumpToVal = "0" + Integer.toString(len) + jumpTo; + } + + try { + if (s != null) { + list = new KeyRecordList( + s.<IKeyRecord>createVirtualList(getDN(), "(&(objectclass=" + + KeyRecord.class.getName() + ")" + filter + ")", + attrs, jumpToVal, sortKey, pageSize)); + } + } finally { + if (s != null) + s.close(); + } + return list; + } + + public BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) throws + EBaseException { + + CMS.debug("KeyRepository: in getLastSerialNumberInRange: low " + + serial_low_bound + " high " + serial_upper_bound); + + if (serial_low_bound == null + || serial_upper_bound == null || serial_low_bound.compareTo(serial_upper_bound) >= 0) { + return null; + } + + String ldapfilter = "(" + "serialno" + "=*" + ")"; + String[] attrs = null; + + KeyRecordList recList = + (KeyRecordList) findKeyRecordsInList(ldapfilter, attrs, serial_upper_bound.toString(10), "serialno", + 5 * -1); + + int size = recList.getSize(); + + CMS.debug("KeyRepository: getLastSerialNumberInRange: recList size " + size); + + if (size <= 0) { + CMS.debug("KeyRepository: getLastSerialNumberInRange: index may be empty"); + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + ret); + return ret; + } + int ltSize = recList.getSizeBeforeJumpTo(); + + CMS.debug("KeyRepository:getLastSerialNumberInRange: ltSize " + ltSize); + + int i; + KeyRecord curRec = null; + + for (i = 0; i < 5; i++) { + curRec = (KeyRecord) recList.getKeyRecord(i); + + if (curRec != null) { + + BigInteger serial = curRec.getSerialNumber(); + + CMS.debug("KeyRepository: getLastCertRecordSerialNo: serialno " + serial); + + if (((serial.compareTo(serial_low_bound) == 0) || (serial.compareTo(serial_low_bound) == 1)) && + ((serial.compareTo(serial_upper_bound) == 0) || (serial.compareTo(serial_upper_bound) == -1))) { + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + serial); + return serial; + } + } else { + CMS.debug("KeyRepository: getLastSerialNumberInRange:found null from getCertRecord"); + } + } + + BigInteger ret = new BigInteger(serial_low_bound.toString(10)); + + ret = ret.add(new BigInteger("-1")); + + CMS.debug("KeyRepository: getLastSerialNumberInRange returning: " + ret); + return ret; + + } + + public void shutdown() { + //if (mKeyStatusUpdateThread != null) + // mKeyStatusUpdateThread.destroy(); + } + +} + +class KeyStatusUpdateThread extends Thread { + KeyRepository _kr = null; + IRepository _rr = null; + int _interval; + + KeyStatusUpdateThread(KeyRepository kr, IRepository rr, String name) { + super(name); + CMS.debug("new KeyStatusUpdateThread"); + + _kr = kr; + _rr = rr; + } + + public void setInterval(int interval) { + _interval = interval; + } + + public void run() { + CMS.debug("Inside run method of KeyStatusUpdateThread"); + + while (true) { + try { + // block the update while another thread + // (such as the CRL Update) is running + CMS.debug("About to start checkRanges"); + synchronized (_kr.mKeyStatusUpdateThread) { + CMS.debug("Starting key checkRanges"); + _kr.checkRanges(); + CMS.debug("key checkRanges done"); + + CMS.debug("Starting request checkRanges"); + _rr.checkRanges(); + CMS.debug("request checkRanges done"); + } + } catch (Exception e) { + CMS.debug("key checkRanges done"); + } + try { + sleep(_interval * 1000); + } catch (InterruptedException e) { + } + } + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/KeyStateMapper.java b/base/common/src/com/netscape/cmscore/dbs/KeyStateMapper.java new file mode 100644 index 000000000..2622cdbc6 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/KeyStateMapper.java @@ -0,0 +1,82 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.keydb.KeyState; + +/** + * A class represents a key state mapper. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class KeyStateMapper implements IDBAttrMapper { + + private String mLdapName = null; + + public KeyStateMapper(String ldapName) { + mLdapName = ldapName; + } + + public Enumeration<String> getSupportedLDAPAttributeNames() { + Vector<String> v = new Vector<String>(); + + v.addElement(mLdapName); + return v.elements(); + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + ((KeyState) obj).toString())); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) { + return; + } + parent.set(name, KeyState.toKeyState( + ((String) attr.getStringValues().nextElement()))); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/LdapFilterConverter.java b/base/common/src/com/netscape/cmscore/dbs/LdapFilterConverter.java new file mode 100644 index 000000000..ff867bf52 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/LdapFilterConverter.java @@ -0,0 +1,62 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Hashtable; + +import com.netscape.certsrv.base.AttributeNameHelper; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IFilterConverter; + +/** + * A class represents a filter converter + * that understands how to convert a attribute + * type from one defintion to another. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class LdapFilterConverter implements IFilterConverter { + + private Hashtable<String, IDBAttrMapper> mReg = null; + + /** + * Constructs filter convertor. + */ + public LdapFilterConverter(Hashtable<String, IDBAttrMapper> reg) { + mReg = reg; + } + + /** + * Converts database filter to ldap filter. + */ + public String convert(String name, String op, String value) { + AttributeNameHelper h = new AttributeNameHelper(name); + IDBAttrMapper mapper = (IDBAttrMapper) mReg.get( + h.getPrefix().toLowerCase()); + + if (mapper == null) + return null; + try { + return mapper.mapSearchFilter(name, op, value); + } catch (EBaseException e) { + } + return null; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/LongMapper.java b/base/common/src/com/netscape/cmscore/dbs/LongMapper.java new file mode 100644 index 000000000..b4d6c75d6 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/LongMapper.java @@ -0,0 +1,119 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java Long object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class LongMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs Long mapper. + */ + public LongMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Returns a list of supported ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object into ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + LongToDB((Long) obj))); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + parent.set(name, LongFromDB( + (String) attr.getStringValues().nextElement())); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + String v = null; + + try { + if (value.startsWith("0x") || value.startsWith("0X")) { + v = LongToDB(Long.valueOf(value.substring(2), 16)); + } else { + v = LongToDB(Long.valueOf(value)); + } + } catch (NumberFormatException e) { + v = value; + } + return mLdapName + op + v; + } + + public static String LongToDB(Long i) { + int len = i.toString().length(); + String ret = null; + + if (len < 10) { + ret = "0" + Integer.toString(len) + i.toString(); + } else { + ret = Integer.toString(len) + i.toString(); + } + return ret; + } + + public static Long LongFromDB(String i) { + String s = i.substring(2); + + // possibly check length + return new Long(s); + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/MetaInfoMapper.java b/base/common/src/com/netscape/cmscore/dbs/MetaInfoMapper.java new file mode 100644 index 000000000..9b224508c --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/MetaInfoMapper.java @@ -0,0 +1,124 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represent mapper for metainfo attribute. Metainfo + * is in format of the following: + * + * <PRE> + * metaInfoType:metaInfoValue + * metaInfoType:metaInfoValue + * metaInfoType:metaInfoValue + * metaInfoType:metaInfoValue + * </PRE> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class MetaInfoMapper implements IDBAttrMapper { + + public static final String SEP = ":"; + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs a metainfo object. + */ + public MetaInfoMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Returns a list of supported ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object into ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + MetaInfo info = (MetaInfo) obj; + Enumeration<String> e = info.getElements(); + + if (!e.hasMoreElements()) + return; // dont add anything + LDAPAttribute attr = new LDAPAttribute(mLdapName); + + while (e.hasMoreElements()) { + String s = null; + String attrName = e.nextElement(); + String value = (String) info.get(attrName); + + s = attrName + SEP + value; + attr.addValue(s); + } + attrs.add(attr); + } + + /** + * Maps LDAP attributes into object, and put the object into + * 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + @SuppressWarnings("unchecked") + Enumeration<String> values = attr.getStringValues(); + MetaInfo info = new MetaInfo(); + + while (values.hasMoreElements()) { + String s = values.nextElement(); + StringTokenizer st = new StringTokenizer(s, SEP); + + info.set(st.nextToken(), st.nextToken()); + } + parent.set(name, info); + } + + /** + * Map search filters into LDAP search filter. + * Possible search filter: + * (&(metaInfo=reserver0:value0)(metaInfo=reserved1:value1)) + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/ObjectStreamMapper.java b/base/common/src/com/netscape/cmscore/dbs/ObjectStreamMapper.java new file mode 100644 index 000000000..f77a36ed4 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/ObjectStreamMapper.java @@ -0,0 +1,136 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents ann attribute mapper that maps + * a Java object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class ObjectStreamMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs object stream mapper. + */ + public ObjectStreamMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of supported ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) + throws EBaseException { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream os = new ObjectOutputStream(bos); + + os.writeObject(obj); + byte data[] = bos.toByteArray(); + if (data == null) { + CMS.debug("ObjectStreamMapper:mapObjectToLDAPAttributeSet " + + name + " size=0"); + } else { + CMS.debug("ObjectStreamMapper:mapObjectToLDAPAttributeSet " + + name + " size=" + data.length); + } + attrs.add(new LDAPAttribute(mLdapName, + data)); + } catch (IOException e) { + + /*LogDoc + * + * @phase Maps object to ldap attribute set + * @message ObjectStreamMapper: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_OBJECTSTREAM_MAPPER_ERROR", + e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_SERIALIZE_FAILED", name)); + } + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + try { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) { + return; + } + ByteArrayInputStream bis = new ByteArrayInputStream( + (byte[]) attr.getByteValues().nextElement()); + ObjectInputStream is = new ObjectInputStream(bis); + + parent.set(name, is.readObject()); + } catch (IOException e) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } catch (ClassNotFoundException e) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/PublicKeyMapper.java b/base/common/src/com/netscape/cmscore/dbs/PublicKeyMapper.java new file mode 100644 index 000000000..8b66d02ca --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/PublicKeyMapper.java @@ -0,0 +1,136 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cmscore.cert.CertUtils; + +/** + * A class represents an attribute mapper that maps + * a public key data into LDAP attribute and + * vice versa. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class PublicKeyMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs a byte array mapper. + */ + public PublicKeyMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Lists a list of supported ldap attribute names. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps object to ldap attribute set. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, (byte[]) obj)); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) { + return; + } + parent.set(name, (byte[]) attr.getByteValues().nextElement()); + } + + /** + * Maps search filters into LDAP search filter. It knows + * how to extract public key from the certificate. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + int i = value.indexOf("#"); + + if (i != -1) { + //String tag = value.substring(0, i); + String val = value.substring(i + 1); + + try { + if (val.startsWith("\"")) { + val = val.substring(1, val.length() - 1); + } + X509Certificate cert = CertUtils.mapCert(val); + PublicKey key = cert.getPublicKey(); + byte pub[] = key.getEncoded(); + + return mLdapName + op + escapeBinaryData(pub); + } catch (Exception e) { + + /*LogDoc + * + * @phase Maps search filters into LDAP search filter + * @message PublicKeyMapper: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_PUBLICKEY_MAPPER_ERROR", + e.toString())); + } + } + return mLdapName + op + value; + } + + public static String escapeBinaryData(byte data[]) { + String result = ""; + + for (int i = 0; i < data.length; i++) { + int v = 0xff & data[i]; + + result = result + "\\" + (v < 16 ? "0" : "") + + Integer.toHexString(v); + } + return result; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/ReplicaIDRepository.java b/base/common/src/com/netscape/cmscore/dbs/ReplicaIDRepository.java new file mode 100644 index 000000000..46ab07385 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/ReplicaIDRepository.java @@ -0,0 +1,83 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.replicadb.IReplicaIDRepository; + +/** + * A class represents a replica repository. It + * creates unique managed replica IDs. + * <P> + * + * @author alee + * @version $Revision$, $Date$ + */ +public class ReplicaIDRepository extends Repository + implements IReplicaIDRepository { + + private IDBSubsystem mDBService; + private String mBaseDN; + + /** + * Constructs a certificate repository. + */ + public ReplicaIDRepository(IDBSubsystem dbService, int increment, String baseDN) + throws EDBException { + super(dbService, increment, baseDN); + mBaseDN = baseDN; + mDBService = dbService; + } + + /** + * Returns last serial number in given range + */ + public BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) + throws EBaseException { + CMS.debug("ReplicaIDReposoitory: in getLastSerialNumberInRange: low " + + serial_low_bound + " high " + serial_upper_bound); + if (serial_low_bound == null + || serial_upper_bound == null || serial_low_bound.compareTo(serial_upper_bound) >= 0) { + return null; + } + BigInteger ret = new BigInteger(getMinSerial()); + if ((ret == null) || (ret.compareTo(serial_upper_bound) > 0) || (ret.compareTo(serial_low_bound) < 0)) { + return null; + } + return ret; + } + + /** + * Retrieves DN of this repository. + */ + public String getDN() { + return mBaseDN; + } + + /** + * Retrieves backend database handle. + */ + public IDBSubsystem getDBSubsystem() { + return mDBService; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/Repository.java b/base/common/src/com/netscape/cmscore/dbs/Repository.java new file mode 100644 index 000000000..aadfb888a --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/Repository.java @@ -0,0 +1,497 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.IDBSSession; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.keydb.IKeyRepository; +import com.netscape.certsrv.dbs.replicadb.IReplicaIDRepository; +import com.netscape.certsrv.dbs.repository.IRepository; +import com.netscape.certsrv.dbs.repository.IRepositoryRecord; + +/** + * A class represents a generic repository. It maintains unique + * serial number within repository. + * <P> + * To build domain specific repository, subclass should be created. + * <P> + * + * @author galperin + * @author thomask + * @version $Revision: 1.4 + * + * $, $Date$ + */ + +public abstract class Repository implements IRepository { + + private static final BigInteger BI_ONE = new BigInteger("1"); + private BigInteger BI_INCREMENT = null; + private static final BigInteger BI_ZERO = new BigInteger("0"); + // (the next serialNo to be issued) - 1 + private BigInteger mSerialNo = null; + // the serialNo attribute stored in db + private BigInteger mNext = null; + + private String mMaxSerial = null; + private String mMinSerial = null; + private String mNextMaxSerial = null; + private String mNextMinSerial = null; + + private BigInteger mMinSerialNo = null; + private BigInteger mMaxSerialNo = null; + private BigInteger mNextMinSerialNo = null; + private BigInteger mNextMaxSerialNo = null; + + private BigInteger mIncrementNo = null; + private BigInteger mLowWaterMarkNo = null; + + private IDBSubsystem mDB = null; + private String mBaseDN = null; + private boolean mInit = false; + private int mRadix = 10; + private int mRepo = -1; + + private BigInteger mLastSerialNo = null; + + /** + * Constructs a repository. + * <P> + */ + public Repository(IDBSubsystem db, int increment, String baseDN) + throws EDBException { + mDB = db; + mBaseDN = baseDN; + + BI_INCREMENT = new BigInteger(Integer.toString(increment)); + + /* + // register schema + IDBRegistry reg = db.getRegistry(); + if (!reg.isObjectClassRegistered(RepositoryRecord.class.getName())) { + String repRecordOC[] = new String[2]; + repRecordOC[0] = RepositorySchema.LDAP_OC_TOP; + repRecordOC[1] = RepositorySchema.LDAP_OC_REPOSITORY; + reg.registerObjectClass(RepositoryRecord.class.getName(), repRecordOC); + } + if (!reg.isAttributeRegistered(RepositoryRecord.ATTR_SERIALNO)) { + reg.registerAttribute(RepositoryRecord.ATTR_SERIALNO, + new BigIntegerMapper(RepositorySchema.LDAP_ATTR_SERIALNO)); + } + */ + } + + /** + * Resets serial number. + */ + public void resetSerialNumber(BigInteger serial) throws EBaseException { + IDBSSession s = mDB.createSession(); + + try { + String name = mBaseDN; + ModificationSet mods = new ModificationSet(); + mods.add(IRepositoryRecord.ATTR_SERIALNO, + Modification.MOD_REPLACE, serial); + s.modify(name, mods); + } finally { + if (s != null) + s.close(); + } + } + + /** + * Retrieves the next serial number attr in db. + * <P> + * + * @return next serial number + */ + protected BigInteger getSerialNumber() throws EBaseException { + IDBSSession s = mDB.createSession(); + + CMS.debug("Repository: getSerialNumber."); + RepositoryRecord rec = null; + + try { + if (s != null) + rec = (RepositoryRecord) s.read(mBaseDN); + } finally { + if (s != null) + s.close(); + } + + if (rec == null) { + CMS.debug("Repository::getSerialNumber() - " + + "- rec is null!"); + throw new EBaseException("rec is null"); + } + + BigInteger serial = rec.getSerialNumber(); + + if (!mInit) { + // cms may crash after issue a cert but before update + // the serial number record + try { + IDBObj obj = s.read("cn=" + + serial + "," + mBaseDN); + + if (obj != null) { + serial = serial.add(BI_ONE); + setSerialNumber(serial); + } + } catch (EBaseException e) { + // do nothing + } + mInit = true; + } + return serial; + } + + /** + * Updates the serial number to the specified in db. + * <P> + * + * @param num serial number + */ + protected void setSerialNumber(BigInteger num) throws EBaseException { + + CMS.debug("Repository:setSerialNumber " + num.toString()); + + return; + + } + + /** + * Get the maximum serial number. + * + * @return maximum serial number + */ + public String getMaxSerial() { + return mMaxSerial; + } + + /** + * Set the maximum serial number. + * + * @param serial maximum number + * @exception EBaseException failed to set maximum serial number + */ + public void setMaxSerial(String serial) throws EBaseException { + BigInteger maxSerial = null; + CMS.debug("Repository:setMaxSerial " + serial); + + maxSerial = new BigInteger(serial, mRadix); + if (maxSerial != null) { + mMaxSerial = serial; + mMaxSerialNo = maxSerial; + } + } + + /** + * Get the maximum serial number in next range. + * + * @return maximum serial number in next range + */ + public String getNextMaxSerial() { + return mNextMaxSerial; + } + + /** + * Set the maximum serial number in next range + * + * @param serial maximum number in next range + * @exception EBaseException failed to set maximum serial number in next range + */ + public void setNextMaxSerial(String serial) throws EBaseException { + BigInteger maxSerial = null; + CMS.debug("Repository:setNextMaxSerial " + serial); + + maxSerial = new BigInteger(serial, mRadix); + if (maxSerial != null) { + mNextMaxSerial = serial; + mNextMaxSerialNo = maxSerial; + } + + return; + } + + /** + * Get the minimum serial number. + * + * @return minimum serial number + */ + public String getMinSerial() { + return mMinSerial; + } + + /** + * init serial number cache + */ + private void initCache() throws EBaseException { + mNext = getSerialNumber(); + mRadix = 10; + + CMS.debug("Repository: in InitCache"); + + if (this instanceof ICertificateRepository) { + CMS.debug("Repository: Instance of Certificate Repository."); + mRadix = 16; + mRepo = IDBSubsystem.CERTS; + } else if (this instanceof IKeyRepository) { + // Key Repository uses the same configuration parameters as Certificate + // Repository. This is ok because they are on separate subsystems. + CMS.debug("Repository: Instance of Key Repository"); + mRadix = 16; + mRepo = IDBSubsystem.CERTS; + } else if (this instanceof IReplicaIDRepository) { + CMS.debug("Repository: Instance of Replica ID repository"); + mRepo = IDBSubsystem.REPLICA_ID; + } else { + // CRLRepository subclasses this too, but does not use serial number stuff + CMS.debug("Repository: Instance of Request Repository or CRLRepository."); + mRepo = IDBSubsystem.REQUESTS; + } + + mMinSerial = mDB.getMinSerialConfig(mRepo); + mMaxSerial = mDB.getMaxSerialConfig(mRepo); + mNextMinSerial = mDB.getNextMinSerialConfig(mRepo); + mNextMaxSerial = mDB.getNextMaxSerialConfig(mRepo); + String increment = mDB.getIncrementConfig(mRepo); + String lowWaterMark = mDB.getLowWaterMarkConfig(mRepo); + + CMS.debug("Repository: minSerial " + mMinSerial + " maxSerial: " + mMaxSerial); + + if (mMinSerial != null) + mMinSerialNo = new BigInteger(mMinSerial, mRadix); + + if (mMaxSerial != null) + mMaxSerialNo = new BigInteger(mMaxSerial, mRadix); + + if (mNextMinSerial != null) + mNextMinSerialNo = new BigInteger(mNextMinSerial, mRadix); + + if (mNextMaxSerial != null) + mNextMaxSerialNo = new BigInteger(mNextMaxSerial, mRadix); + + if (lowWaterMark != null) + mLowWaterMarkNo = new BigInteger(lowWaterMark, mRadix); + + if (increment != null) + mIncrementNo = new BigInteger(increment, mRadix); + + BigInteger theSerialNo = null; + theSerialNo = getLastSerialNumberInRange(mMinSerialNo, mMaxSerialNo); + + if (theSerialNo != null) { + + mLastSerialNo = new BigInteger(theSerialNo.toString()); + CMS.debug("Repository: mLastSerialNo: " + mLastSerialNo.toString()); + + } else { + + throw new EBaseException("Error in obtaining the last serial number in the repository!"); + + } + + } + + /** + * get the next serial number in cache + */ + public BigInteger getTheSerialNumber() throws EBaseException { + + CMS.debug("Repository:In getTheSerialNumber "); + if (mLastSerialNo == null) + initCache(); + BigInteger serial = new BigInteger((mLastSerialNo.add(BI_ONE)).toString()); + + if (mMaxSerialNo != null && serial.compareTo(mMaxSerialNo) > 0) + return null; + else + return serial; + } + + /** + * Updates the serial number to the specified in db and cache. + * <P> + * + * @param num serial number + */ + public void setTheSerialNumber(BigInteger num) throws EBaseException { + // mSerialNo is already set. But just in case + + CMS.debug("Repository:In setTheSerialNumber " + num.toString()); + if (mLastSerialNo == null) + initCache(); + + if (num.compareTo(mSerialNo) <= 0) { + throw new EDBException(CMS.getUserMessage("CMS_DBS_SETBACK_SERIAL", + mSerialNo.toString(16))); + } + // write the config parameter. It's needed in case the serialNum gap + // < BI_INCREMENT and server restart right afterwards. + mDB.setNextSerialConfig(num); + + mSerialNo = num.subtract(BI_ONE); + mNext = num.add(BI_INCREMENT); + setSerialNumber(mNext); + } + + /** + * Retrieves the next serial number, and also increase the + * serial number by one. + * <P> + * + * @return serial number + */ + public synchronized BigInteger getNextSerialNumber() throws + EBaseException { + + CMS.debug("Repository: in getNextSerialNumber. "); + + if (mLastSerialNo == null) { + initCache(); + + mLastSerialNo = mLastSerialNo.add(BI_ONE); + + } else { + mLastSerialNo = mLastSerialNo.add(BI_ONE); + } + + if (mLastSerialNo == null) { + CMS.debug("Repository::getNextSerialNumber() " + + "- mLastSerialNo is null!"); + throw new EBaseException("mLastSerialNo is null"); + } + + // check if we have reached the end of the range + // if so, move to next range + if (mLastSerialNo.compareTo(mMaxSerialNo) > 0) { + if (mDB.getEnableSerialMgmt()) { + CMS.debug("Reached the end of the range. Attempting to move to next range"); + mMinSerialNo = mNextMinSerialNo; + mMaxSerialNo = mNextMaxSerialNo; + mLastSerialNo = mMinSerialNo; + mNextMinSerialNo = null; + mNextMaxSerialNo = null; + if ((mMaxSerialNo == null) || (mMinSerialNo == null)) { + throw new EDBException(CMS.getUserMessage("CMS_DBS_LIMIT_REACHED", + mLastSerialNo.toString())); + } + + // persist the changes + mDB.setMinSerialConfig(mRepo, mMinSerialNo.toString()); + mDB.setMaxSerialConfig(mRepo, mMaxSerialNo.toString()); + mDB.setNextMinSerialConfig(mRepo, null); + mDB.setNextMaxSerialConfig(mRepo, null); + } else { + throw new EDBException(CMS.getUserMessage("CMS_DBS_LIMIT_REACHED", + mLastSerialNo.toString())); + } + } + + BigInteger retSerial = new BigInteger(mLastSerialNo.toString()); + + CMS.debug("Repository: getNextSerialNumber: returning retSerial " + retSerial); + return retSerial; + } + + /** + * Checks to see if a new range is needed, or if we have reached the end of the + * current range, or if a range conflict has occurred. + * + * @exception EBaseException failed to check next range for conflicts + */ + public void checkRanges() throws EBaseException { + if (!mDB.getEnableSerialMgmt()) { + CMS.debug("Serial Management not enabled. Returning .. "); + return; + } + if (CMS.getEESSLPort() == null) { + CMS.debug("Server not completely started. Returning .."); + return; + } + + if (mLastSerialNo == null) + initCache(); + + BigInteger numsInRange = mMaxSerialNo.subtract(mLastSerialNo); + BigInteger numsInNextRange = null; + BigInteger numsAvail = null; + CMS.debug("Serial numbers left in range: " + numsInRange.toString()); + CMS.debug("Last Serial Number: " + mLastSerialNo.toString()); + if ((mNextMaxSerialNo != null) && (mNextMinSerialNo != null)) { + numsInNextRange = mNextMaxSerialNo.subtract(mNextMinSerialNo); + numsAvail = numsInRange.add(numsInNextRange); + CMS.debug("Serial Numbers in next range: " + numsInNextRange.toString()); + CMS.debug("Serial Numbers available: " + numsAvail.toString()); + } else { + numsAvail = numsInRange; + CMS.debug("Serial Numbers available: " + numsAvail.toString()); + } + + if ((numsAvail.compareTo(mLowWaterMarkNo) < 0) && (!CMS.isPreOpMode())) { + CMS.debug("Low water mark reached. Requesting next range"); + mNextMinSerialNo = new BigInteger(mDB.getNextRange(mRepo), mRadix); + if (mNextMinSerialNo == null) { + CMS.debug("Next Range not available"); + } else { + CMS.debug("nNextMinSerialNo has been set to " + mNextMinSerialNo.toString(mRadix)); + mNextMaxSerialNo = mNextMinSerialNo.add(mIncrementNo); + numsAvail = numsAvail.add(mIncrementNo); + mDB.setNextMinSerialConfig(mRepo, mNextMinSerialNo.toString(mRadix)); + mDB.setNextMaxSerialConfig(mRepo, mNextMaxSerialNo.toString(mRadix)); + } + } + + if (numsInRange.compareTo(mLowWaterMarkNo) < 0) { + // check for a replication error + CMS.debug("Checking for a range conflict"); + if (mDB.hasRangeConflict(mRepo)) { + CMS.debug("Range Conflict found! Removing next range."); + mNextMaxSerialNo = null; + mNextMinSerialNo = null; + mDB.setNextMinSerialConfig(mRepo, null); + mDB.setNextMaxSerialConfig(mRepo, null); + } + } + } + + /** + * Sets whether serial number management is enabled for certs + * and requests. + * + * @param value true/false + * @exception EBaseException failed to set + */ + public void setEnableSerialMgmt(boolean value) throws EBaseException { + mDB.setEnableSerialMgmt(value); + } + + public abstract BigInteger getLastSerialNumberInRange(BigInteger serial_low_bound, BigInteger serial_upper_bound) + throws + EBaseException; +} diff --git a/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java b/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java new file mode 100644 index 000000000..8f90723cd --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/RepositoryRecord.java @@ -0,0 +1,111 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Vector; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.repository.IRepositoryRecord; + +/** + * A class represents a repository record. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class RepositoryRecord implements IRepositoryRecord { + + /** + * + */ + private static final long serialVersionUID = 1648450747848783853L; + private BigInteger mSerialNo = null; + private String mPublishingStatus = null; + + protected static Vector<String> mNames = new Vector<String>(); + static { + mNames.addElement(IRepositoryRecord.ATTR_SERIALNO); + mNames.addElement(IRepositoryRecord.ATTR_PUB_STATUS); + } + + /** + * Constructs a repository record. + * <P> + */ + public RepositoryRecord() { + } + + /** + * Sets attribute. + */ + public void set(String name, Object obj) throws EBaseException { + if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_SERIALNO)) { + mSerialNo = (BigInteger) obj; + } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_PUB_STATUS)) { + mPublishingStatus = (String) obj; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Retrieves attribute from this record. + */ + public Object get(String name) throws EBaseException { + if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_SERIALNO)) { + return mSerialNo; + } else if (name.equalsIgnoreCase(IRepositoryRecord.ATTR_PUB_STATUS)) { + return mPublishingStatus; + } else { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + } + + /** + * Deletes an attribute. + */ + public void delete(String name) throws EBaseException { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", name)); + } + + /** + * Retrieves a list of attribute names. + */ + public Enumeration<String> getElements() { + return mNames.elements(); + } + + public Enumeration<String> getSerializableAttrNames() { + return mNames.elements(); + } + + /** + * Retrieves serial number. + */ + public BigInteger getSerialNumber() { + return mSerialNo; + } + + public String getPublishingStatus() { + return mPublishingStatus; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java b/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java new file mode 100644 index 000000000..4a0cf4155 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/RepositorySchema.java @@ -0,0 +1,34 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +/** + * A class represents a collection of repository-specific + * schema information. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class RepositorySchema { + + public static final String LDAP_OC_TOP = "top"; + public static final String LDAP_OC_REPOSITORY = "repository"; + public static final String LDAP_ATTR_SERIALNO = "serialno"; + public static final String LDAP_ATTR_PUB_STATUS = "publishingStatus"; +} diff --git a/base/common/src/com/netscape/cmscore/dbs/RevocationInfo.java b/base/common/src/com/netscape/cmscore/dbs/RevocationInfo.java new file mode 100644 index 000000000..00ca0034b --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/RevocationInfo.java @@ -0,0 +1,78 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.io.Serializable; +import java.util.Date; + +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; + +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; + +/** + * A class represents a certificate revocation info. This + * object is written as an attribute of certificate record + * which essentially signifies a revocation act. + * <P> + * + * @author galperin + * @version $Revision$, $Date$ + */ +public class RevocationInfo implements IRevocationInfo, Serializable { + + /** + * + */ + private static final long serialVersionUID = -157323417902547417L; + private Date mRevocationDate = null; + private CRLExtensions mCRLEntryExtensions = null; + + /** + * Constructs revocation info. + */ + public RevocationInfo() { + } + + /** + * Constructs revocation info used by revocation + * request implementation. + * + * @param reason if not null contains CRL entry extension + * that specifies revocation reason + * @see CRLReasonExtension + */ + public RevocationInfo(Date revocationDate, CRLExtensions exts) { + mRevocationDate = revocationDate; + mCRLEntryExtensions = exts; + } + + /** + * Retrieves revocation date. + */ + public Date getRevocationDate() { + return mRevocationDate; + } + + /** + * Retrieves CRL extensions. + */ + public CRLExtensions getCRLEntryExtensions() { + return mCRLEntryExtensions; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/RevocationInfoMapper.java b/base/common/src/com/netscape/cmscore/dbs/RevocationInfoMapper.java new file mode 100644 index 000000000..7cf39dcef --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/RevocationInfoMapper.java @@ -0,0 +1,171 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.Extension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.RevocationReason; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.cmscore.util.Debug; + +/** + * A class represents a mapper to serialize + * revocation information into database. + * <P> + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class RevocationInfoMapper implements IDBAttrMapper { + + protected static Vector<String> mNames = new Vector<String>(); + static { + mNames.addElement(CertDBSchema.LDAP_ATTR_REVO_INFO); + } + + /** + * Constructs revocation information mapper. + */ + public RevocationInfoMapper() { + } + + public Enumeration<String> getSupportedLDAPAttributeNames() { + return mNames.elements(); + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) + throws EBaseException { + try { + // in format of <date>;<extensions> + String value = ""; + RevocationInfo info = (RevocationInfo) obj; + Date d = info.getRevocationDate(); + + value = DateMapper.dateToDB(d); + CRLExtensions exts = info.getCRLEntryExtensions(); + // CRLExtension's DER encoding and decoding does not work! + // That is why we need to do our own serialization. + Enumeration<Extension> e = exts.getElements(); + + while (e.hasMoreElements()) { + Extension ext = e.nextElement(); + + if (ext instanceof CRLReasonExtension) { + RevocationReason reason = + ((CRLReasonExtension) ext).getReason(); + + value = value + ";CRLReasonExtension=" + + Integer.toString(reason.toInt()); + } else if (ext instanceof InvalidityDateExtension) { + Date invalidityDate = + ((InvalidityDateExtension) ext).getInvalidityDate(); + + value = value + ";InvalidityDateExtension=" + + DateMapper.dateToDB(invalidityDate); + } else { + Debug.trace("XXX skipped extension"); + } + } + attrs.add(new LDAPAttribute(CertDBSchema.LDAP_ATTR_REVO_INFO, + value)); + } catch (Exception e) { + Debug.trace(e.toString()); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_SERIALIZE_FAILED", name)); + } + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + try { + LDAPAttribute attr = attrs.getAttribute( + CertDBSchema.LDAP_ATTR_REVO_INFO); + + if (attr == null) + return; + String value = (String) attr.getStringValues().nextElement(); + int i = value.indexOf(';'); // look for 1st ";" + String str = null; + CRLExtensions exts = new CRLExtensions(); + Date d = null; + + if (i == -1) { + // only date found; no extensions + d = DateMapper.dateFromDB(value); + } else { + String s = value; + + str = s.substring(0, i); + d = DateMapper.dateFromDB(str); + s = s.substring(i + 1); + do { + i = s.indexOf(';'); + if (i == -1) { + str = s; + } else { + str = s.substring(0, i); + s = s.substring(i + 1); + } + if (str.startsWith("CRLReasonExtension=")) { + String reasonStr = str.substring(19); + RevocationReason reason = RevocationReason.fromInt( + Integer.parseInt(reasonStr)); + CRLReasonExtension ext = new CRLReasonExtension(reason); + + exts.set(CRLReasonExtension.NAME, ext); + } else if (str.startsWith("InvalidityDateExtension=")) { + String invalidityDateStr = str.substring(24); + Date invalidityDate = DateMapper.dateFromDB(invalidityDateStr); + InvalidityDateExtension ext = + new InvalidityDateExtension(invalidityDate); + + exts.set(InvalidityDateExtension.NAME, ext); + } else { + Debug.trace("XXX skipped extension"); + } + } while (i != -1); + } + RevocationInfo info = new RevocationInfo(d, exts); + + parent.set(name, info); + } catch (Exception e) { + Debug.trace(e.toString()); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } + } + + public String mapSearchFilter(String name, String op, String value) + throws EBaseException { + return CertDBSchema.LDAP_ATTR_REVO_INFO + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/StringMapper.java b/base/common/src/com/netscape/cmscore/dbs/StringMapper.java new file mode 100644 index 000000000..710a17875 --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/StringMapper.java @@ -0,0 +1,95 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.NoSuchElementException; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java String object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class StringMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs string mapper. + */ + public StringMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of supported ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps attribute value to ldap attributes. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, (String) obj)); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) + throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) { + return; + } + try { + parent.set(name, (String) + attr.getStringValues().nextElement()); + } catch (NoSuchElementException e) { + // attribute present, but without value + } + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/StringVectorMapper.java b/base/common/src/com/netscape/cmscore/dbs/StringVectorMapper.java new file mode 100644 index 000000000..7a465231b --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/StringVectorMapper.java @@ -0,0 +1,111 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; + +/** + * A class represents ann attribute mapper that maps + * a Java String object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class StringVectorMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + /** + * Constructs string vector mapper. + */ + public StringVectorMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of supported ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps attribute value to ldap attributes. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + @SuppressWarnings("unchecked") + Vector<String> v = (Vector<String>) obj; + int s = v.size(); + + if (s == 0) { + return; + } + String m[] = new String[s]; + + for (int i = 0; i < s; i++) { + m[i] = v.elementAt(i); + } + attrs.add(new LDAPAttribute(mLdapName, m)); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) + return; + @SuppressWarnings("unchecked") + Enumeration<String> e = attr.getStringValues(); + Vector<String> v = new Vector<String>(); + + while (e.hasMoreElements()) { + v.addElement(e.nextElement()); + } + if (v.size() == 0) + return; + String m[] = new String[v.size()]; + + v.copyInto(m); + parent.set(name, m); + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/X500NameMapper.java b/base/common/src/com/netscape/cmscore/dbs/X500NameMapper.java new file mode 100644 index 000000000..0bf3bf7da --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/X500NameMapper.java @@ -0,0 +1,111 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.security.x509.X500Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.logging.ILogger; + +/** + * A class represents ann attribute mapper that maps + * a Java X500Name object into LDAP attribute, + * and vice versa. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class X500NameMapper implements IDBAttrMapper { + + private String mLdapName = null; + private Vector<String> v = new Vector<String>(); + + private ILogger mLogger = CMS.getLogger(); + + /** + * Constructs X500Name mapper. + */ + public X500NameMapper(String ldapName) { + mLdapName = ldapName; + v.addElement(mLdapName); + } + + /** + * Retrieves a list of ldap attributes. + */ + public Enumeration<String> getSupportedLDAPAttributeNames() { + return v.elements(); + } + + /** + * Maps attribute value to ldap attributes. + */ + public void mapObjectToLDAPAttributeSet(IDBObj parent, + String name, Object obj, LDAPAttributeSet attrs) + throws EBaseException { + attrs.add(new LDAPAttribute(mLdapName, + ((X500Name) obj).toString())); + } + + /** + * Maps LDAP attributes into object, and put the object + * into 'parent'. + */ + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + LDAPAttribute attr = attrs.getAttribute(mLdapName); + + if (attr == null) { + return; + } + try { + parent.set(name, new X500Name((String) + attr.getStringValues().nextElement())); + } catch (IOException e) { + + /*LogDoc + * + * @phase Maps LDAP attributes into object + * @message X500NameMapper: <exception thrown> + */ + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_DB, ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_DBS_X500NAME_MAPPER_ERROR", + e.toString())); + throw new EDBException( + CMS.getUserMessage("CMS_DBS_DESERIALIZE_FAILED", name)); + } + } + + /** + * Maps search filters into LDAP search filter. + */ + public String mapSearchFilter(String name, String op, + String value) throws EBaseException { + return mLdapName + op + value; + } +} diff --git a/base/common/src/com/netscape/cmscore/dbs/X509CertImplMapper.java b/base/common/src/com/netscape/cmscore/dbs/X509CertImplMapper.java new file mode 100644 index 000000000..18f0c8e3d --- /dev/null +++ b/base/common/src/com/netscape/cmscore/dbs/X509CertImplMapper.java @@ -0,0 +1,369 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program 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 for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.cmscore.dbs; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +import netscape.ldap.LDAPAttribute; +import netscape.ldap.LDAPAttributeSet; +import netscape.security.extensions.NSCertTypeExtension; +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.Extension; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509Key; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.AttributeNameHelper; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.dbs.EDBException; +import com.netscape.certsrv.dbs.IDBAttrMapper; +import com.netscape.certsrv.dbs.IDBObj; +import com.netscape.certsrv.dbs.certdb.ICertRecord; + +/** + * A class represents a mapper to serialize + * x509 certificate into database. + * + * @author thomask + * @version $Revision$, $Date$ + */ +public class X509CertImplMapper implements IDBAttrMapper { + + public X509CertImplMapper() { + } + + public Enumeration<String> getSupportedLDAPAttributeNames() { + Vector<String> v = new Vector<String>(); + + v.addElement(CertDBSchema.LDAP_ATTR_NOT_BEFORE); + v.addElement(CertDBSchema.LDAP_ATTR_NOT_AFTER); + v.addElement(CertDBSchema.LDAP_ATTR_DURATION); + v.addElement(CertDBSchema.LDAP_ATTR_EXTENSION); + v.addElement(CertDBSchema.LDAP_ATTR_SUBJECT); + v.addElement(CertDBSchema.LDAP_ATTR_SIGNED_CERT); + v.addElement(CertDBSchema.LDAP_ATTR_VERSION); + v.addElement(CertDBSchema.LDAP_ATTR_ALGORITHM); + v.addElement(CertDBSchema.LDAP_ATTR_SIGNING_ALGORITHM); + v.addElement(CertDBSchema.LDAP_ATTR_PUBLIC_KEY_DATA); + return v.elements(); + } + + public void mapObjectToLDAPAttributeSet(IDBObj parent, String name, + Object obj, LDAPAttributeSet attrs) throws EBaseException { + try { + X509CertImpl cert = (X509CertImpl) obj; + // make information searchable + Date notBefore = cert.getNotBefore(); + + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_NOT_BEFORE, + DateMapper.dateToDB(notBefore))); + Date notAfter = cert.getNotAfter(); + + attrs.add(new LDAPAttribute(CertDBSchema.LDAP_ATTR_NOT_AFTER, + DateMapper.dateToDB(notAfter))); + attrs.add(new LDAPAttribute(CertDBSchema.LDAP_ATTR_DURATION, + DBSUtil.longToDB(notAfter.getTime() - notBefore.getTime()))); + attrs.add(new LDAPAttribute(CertDBSchema.LDAP_ATTR_SUBJECT, + cert.getSubjectDN().getName())); + attrs.add(new LDAPAttribute(CertDBSchema.LDAP_ATTR_PUBLIC_KEY_DATA, cert.getPublicKey().getEncoded())); + // make extension searchable + Set<String> nonCritSet = cert.getNonCriticalExtensionOIDs(); + + if (nonCritSet != null) { + for (Iterator<String> i = nonCritSet.iterator(); i.hasNext();) { + String oid = i.next(); + + if (oid.equals("2.16.840.1.113730.1.1")) { + String extVal = getCertTypeExtensionInfo(cert); + + if (extVal != null) { + oid = oid + ";" + extVal; + } + } else if (oid.equals("2.5.29.19")) { + String extVal = getBasicConstraintsExtensionInfo(cert); + + if (extVal != null) { + oid = oid + ";" + extVal; + } + } + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_EXTENSION, oid)); + } + } + Set<String> critSet = cert.getCriticalExtensionOIDs(); + + if (critSet != null) { + for (Iterator<String> i = critSet.iterator(); i.hasNext();) { + String oid = i.next(); + + if (oid.equals("2.16.840.1.113730.1.1")) { + String extVal = getCertTypeExtensionInfo(cert); + + if (extVal != null) { + oid = oid + ";" + extVal; + } + } else if (oid.equals("2.5.29.19")) { + String extVal = getBasicConstraintsExtensionInfo(cert); + + if (extVal != null) { + oid = oid + ";" + extVal; + } + } + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_EXTENSION, oid)); + } + } + + // something extra; so that we can rebuild the + // object quickly + // if we dont add ";binary", communicator does + // not know how to display the certificate in + // pretty print format. + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_SIGNED_CERT + ";binary", + cert.getEncoded())); + + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_VERSION, + Integer.toString(cert.getVersion()))); + X509Key pubKey = (X509Key) cert.getPublicKey(); + + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_ALGORITHM, + pubKey.getAlgorithmId().getOID().toString())); + attrs.add(new LDAPAttribute( + CertDBSchema.LDAP_ATTR_SIGNING_ALGORITHM, + cert.getSigAlgOID())); + } catch (CertificateEncodingException e) { + throw new EDBException( + CMS.getUserMessage("CMS_DBS_SERIALIZE_FAILED", name)); + } + } + + private String getCertTypeExtensionInfo(X509CertImpl cert) { + try { + Extension ext = cert.getExtension("2.16.840.1.113730.1.1"); + + if (ext == null) { + // sometime time (during installation) it + // is named differently + ext = cert.getExtension(NSCertTypeExtension.NAME); + if (ext == null) + return null; + } + NSCertTypeExtension nsExt = (NSCertTypeExtension) ext; + + String result = ""; + + Boolean sslServer = (Boolean) nsExt.get( + NSCertTypeExtension.SSL_SERVER); + + result += "SSLServer=" + sslServer.toString() + ","; + Boolean sslClient = (Boolean) nsExt.get( + NSCertTypeExtension.SSL_CLIENT); + + result += "SSLClient=" + sslClient.toString() + ","; + Boolean email = (Boolean) nsExt.get( + NSCertTypeExtension.EMAIL); + + result += "Email=" + email.toString() + ","; + Boolean sslCA = (Boolean) nsExt.get( + NSCertTypeExtension.SSL_CA); + + result += "SSLCA=" + sslCA.toString() + ","; + Boolean mailCA = (Boolean) nsExt.get( + NSCertTypeExtension.EMAIL_CA); + + result += "EmailCA=" + mailCA.toString() + ","; + Boolean objectSigning = (Boolean) nsExt.get( + NSCertTypeExtension.OBJECT_SIGNING); + + result += "objectSigning=" + + objectSigning.toString(); + return result; + } catch (Exception e) { + return null; + } + } + + private String getBasicConstraintsExtensionInfo(X509CertImpl cert) { + try { + Extension ext = cert.getExtension("2.5.29.19"); + + if (ext == null) { + // sometime time (during installation) it + // is named differently + ext = cert.getExtension(BasicConstraintsExtension.NAME); + if (ext == null) + return null; + } + BasicConstraintsExtension bcExt = (BasicConstraintsExtension) ext; + + String result = ""; + + Boolean isCA = (Boolean) bcExt.get( + BasicConstraintsExtension.IS_CA); + + result += "isCA=" + isCA.toString() + ","; + Integer pathLen = (Integer) bcExt.get( + BasicConstraintsExtension.PATH_LEN); + + result += "pathLen=" + pathLen.toString(); + return result; + } catch (Exception e) { + return null; + } + } + + public void mapLDAPAttributeSetToObject(LDAPAttributeSet attrs, + String name, IDBObj parent) throws EBaseException { + try { + // rebuild object quickly using binary image + // XXX bad! when we add this attribute, + // we add it as userCertificate, but when + // we retrieve it, DS returns it as + // userCertificate;binary. So I cannot do the + // following: + // LDAPAttribute attr = attrs.getAttribute( + // Schema.LDAP_ATTR_SIGNED_CERT); + + LDAPAttribute attr = attrs.getAttribute( + CertDBSchema.LDAP_ATTR_SIGNED_CERT); + + if (attr == null) { + // YUK! + attr = attrs.getAttribute( + CertDBSchema.LDAP_ATTR_SIGNED_CERT + ";binary"); + } + if (attr != null) { + byte der[] = (byte[]) + attr.getByteValues().nextElement(); + X509CertImpl impl = new X509CertImpl(der); + + parent.set(name, impl); + } + } catch (CertificateException e) { + //throw new EDBException( + // DBResources.FAILED_TO_DESERIALIZE_1, name); + parent.set(name, null); + } catch (Exception e) { + //throw new EDBException( + // DBResources.FAILED_TO_DESERIALIZE_1, name); + parent.set(name, null); + + } + } + + public String mapSearchFilter(String name, String op, String value) + throws EBaseException { + AttributeNameHelper h = new AttributeNameHelper(name); + String suffix = h.getSuffix(); + + if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_NOT_BEFORE)) { + name = CertDBSchema.LDAP_ATTR_NOT_BEFORE; + try { + value = DateMapper.dateToDB(new + Date(Long.parseLong(value))); + } catch (NumberFormatException e) { + } + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_NOT_AFTER)) { + name = CertDBSchema.LDAP_ATTR_NOT_AFTER; + try { + value = DateMapper.dateToDB(new + Date(Long.parseLong(value))); + } catch (NumberFormatException e) { + } + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_SUBJECT)) { + name = CertDBSchema.LDAP_ATTR_SUBJECT; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_PUBLIC_KEY_DATA)) { + name = CertDBSchema.LDAP_ATTR_PUBLIC_KEY_DATA; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_DURATION)) { + name = CertDBSchema.LDAP_ATTR_DURATION; + value = DBSUtil.longToDB(Long.parseLong(value)); + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_VERSION)) { + name = CertDBSchema.LDAP_ATTR_VERSION; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_ALGORITHM)) { + name = CertDBSchema.LDAP_ATTR_ALGORITHM; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_SIGNING_ALGORITHM)) { + name = CertDBSchema.LDAP_ATTR_SIGNING_ALGORITHM; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_SERIAL_NUMBER)) { + name = CertDBSchema.LDAP_ATTR_CERT_RECORD_ID; + } else if (suffix.equalsIgnoreCase(ICertRecord.X509CERT_EXTENSION)) { + name = CertDBSchema.LDAP_ATTR_EXTENSION; + } else if (suffix.equalsIgnoreCase(ICertRecord.ATTR_REVO_INFO)) { + name = CertDBSchema.LDAP_ATTR_REVO_INFO; + value = "*;CRLReasonExtension=" + value + "*"; + } else if (suffix.equalsIgnoreCase("nsExtension.SSLClient")) { + // special case for NS cert type extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.16.840.1.113730.1.1;*SSLClient=true*"; + } else { + value = "2.16.840.1.113730.1.1;*SSLClient=false*"; + } + } else if (suffix.equalsIgnoreCase("nsExtension.SSLServer")) { + // special case for NS cert type extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.16.840.1.113730.1.1;*SSLServer=true*"; + } else { + value = "2.16.840.1.113730.1.1;*SSLServer=false*"; + } + } else if (suffix.equalsIgnoreCase("nsExtension.SecureEmail")) { + // special case for NS cert type extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.16.840.1.113730.1.1;*Email=true*"; + } else { + value = "2.16.840.1.113730.1.1;*Email=false*"; + } + } else if (suffix.equalsIgnoreCase("nsExtension.SubordinateSSLCA")) { + // special case for NS cert type extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.16.840.1.113730.1.1;*SSLCA=true*"; + } else { + value = "2.16.840.1.113730.1.1;*SSLCA=false*"; + } + } else if (suffix.equalsIgnoreCase("nsExtension.SubordinateEmailCA")) { + // special case for NS cert type extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.16.840.1.113730.1.1;*EmailCA=true*"; + } else { + value = "2.16.840.1.113730.1.1;*EmailCA=false*"; + } + } else if (suffix.equalsIgnoreCase("BasicConstraints.isCA")) { + // special case for Basic Constraints extension + name = CertDBSchema.LDAP_ATTR_EXTENSION; + if (value.equals("on")) { + value = "2.5.29.19;*isCA=true*"; + } else { + value = "2.5.29.19;*isCA=false*"; + } + } + return name + op + value; + } +} |