summaryrefslogtreecommitdiffstats
path: root/pki/base/common/src/com/netscape/cms/publish
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/publish')
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/AVAPattern.java592
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapCaSimpleMap.java366
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertCompsMap.java179
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertExactMap.java193
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertSubjMap.java337
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapCrlIssuerCompsMap.java159
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapDNCompsMap.java439
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapEnhancedMap.java639
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/LdapSimpleMap.java320
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/MapAVAPattern.java634
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/MapDNPattern.java202
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/MapRDNPattern.java218
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/mappers/NoMap.java108
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java424
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java408
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java332
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java306
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java367
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java342
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java315
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java351
-rw-r--r--pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java131
22 files changed, 7362 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/AVAPattern.java b/pki/base/common/src/com/netscape/cms/publish/mappers/AVAPattern.java
new file mode 100644
index 000000000..334f0c98f
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/AVAPattern.java
@@ -0,0 +1,592 @@
+// --- 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 statement //
+///////////////////////
+
+package com.netscape.cms.publish.mappers;
+
+
+///////////////////////
+// import statements //
+///////////////////////
+
+/* cert server imports */
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+/* LDAP imports */
+import netscape.ldap.*;
+
+/* security imports */
+import netscape.security.util.*;
+import netscape.security.x509.*;
+
+/* java sdk imports */
+import java.io.*;
+import java.security.*;
+import java.util.*;
+
+
+//////////////////////
+// class definition //
+//////////////////////
+
+/**
+ * avaPattern is a string representing an ldap
+ * attribute formulated from the certificate
+ * subject name, extension or request attributes.
+ * <p>
+ *
+ * The syntax is
+ * <pre>
+ * avaPattern := constant-value |
+ * "$subj" "." attrName [ "." attrNumber ] |
+ * "$req" "." [ prefix .] attrName [ "." attrNumber ] |
+ * "$ext" "." extName [ "." nameType ] [ "." attrNumber ]
+ * </pre>
+ * <pre>
+ * Example: <i>$ext.SubjectAlternativeName.RFC822Name.1</i>
+ * cert subjectAltName is rfc822Name: jjames@mcom.com
+ * <p>
+ * The ldap attribute formulated will be : <br>
+ * jjames@mcom.com
+ * <p>
+ * The first rfc822name value in the subjAltName extension. <br>
+ * <p>
+ * </pre>
+ * If a request attribute or subject DN component does not exist,
+ * the attribute is skipped.
+ *
+ * @version $Revision$, $Date$
+ */
+class AVAPattern {
+ ////////////////
+ // parameters //
+ ////////////////
+
+ /* the value type of the dn component */
+ public static final String TYPE_REQ = "$req";
+ public static final String TYPE_SUBJ = "$subj";
+ public static final String TYPE_EXT = "$ext";
+ public static final String TYPE_CONSTANT = "constant";
+
+ public static final String[] GENERAL_NAME_TYPE = { "ANY",
+ "RFC822Name",
+ "DNSName",
+ "X400Name",
+ "DIRECTORYName",
+ "EDIName",
+ "URIName",
+ "IPAddress",
+ "OIDName"};
+
+ private static final char[] endChars = new char[] { '+', ',' };
+
+ private static final LdapV3DNStrConverter mLdapDNStrConverter =
+ new LdapV3DNStrConverter();
+
+ /* the list of request attributes needed by this AVA */
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attributes needed by this AVA*/
+ protected String[] mCertAttrs = null;
+
+ /* value type */
+ protected String mType = null;
+
+ /* value - could be name of a request attribute or
+ * cert subject attribute or extension name.
+ */
+ protected String mValue = null;
+
+ /* value type - general name type of an
+ * extension attribute if any.
+ */
+ protected String mGNType = null;
+
+ /* prefix - prefix of a request attribute if any. */
+ protected String mPrefix = null;
+
+ /* nth value of the ldap or dn attribute */
+ protected int mElement = 0;
+
+ protected String mTestDN = null;
+
+ /////////////
+ // methods //
+ /////////////
+
+ public AVAPattern(String component)
+ throws ELdapException {
+ if (component == null || component.length() == 0) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", component));
+ }
+
+ parse(new PushbackReader(new StringReader(component)));
+ }
+
+ public AVAPattern(PushbackReader in)
+ throws ELdapException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws ELdapException {
+ int c;
+
+ // skip spaces
+ //System.out.println("============ AVAPattern Begin ===========");
+ //System.out.println("skip spaces");
+
+ try {
+ while ((c = in.read()) == ' ' || c == '\t') {//System.out.println("spaces read "+(char)c);
+ ;
+ }
+ } catch (IOException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "All blank"));
+ }
+
+ if (c == -1) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "All blank"));
+ }
+
+ if (c == '$') {
+ // check for $subj $ext or $req
+ try {
+ c = in.read();
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ if (c == -1) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $subj $ext or $req in ava pattern"));
+ }
+
+ if (c == 'r') {
+ try {
+ if (in.read() != 'e' ||
+ in.read() != 'q' ||
+ in.read() != '.') {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $req in ava pattern"));
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mType = TYPE_REQ;
+ //System.out.println("---- mtype $req");
+ } else if (c == 's') {
+ try {
+ if (in.read() != 'u' ||
+ in.read() != 'b' ||
+ in.read() != 'j' ||
+ in.read() != '.') {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $subj in ava pattern"));
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mType = TYPE_SUBJ;
+ //System.out.println("----- mtype $subj");
+ } else if (c == 'e') {
+ try {
+ if (in.read() != 'x' ||
+ in.read() != 't' ||
+ in.read() != '.') {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $ext in ava pattern"));
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mType = TYPE_EXT;
+ //System.out.println("----- mtype $ext");
+ } else {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "unknown keyword. expecting $subj $ext or $req."));
+ }
+
+ // get request attribute or
+ // cert subject or
+ // extension attribute
+
+ StringBuffer valueBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' &&
+ c != -1 && c != '.' && c != '+') {
+ //System.out.println("mValue read "+(char)c);
+ valueBuf.append((char) c);
+ }
+
+ if (c == '+' || c == ',') { // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mValue = valueBuf.toString().trim();
+ if (mValue.length() == 0) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "$subj $ext or $req attribute name expected"));
+ }
+ //System.out.println("----- mValue "+mValue);
+
+ // get nth dn xxx not nth request attribute .
+ if (c == '.') {
+ StringBuffer attrNumberBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' && c != -1 && c != '.'
+ && c != '+') {
+ //System.out.println("mElement read "+(char)c);
+ attrNumberBuf.append((char) c);
+ }
+
+ if (c == ',' || c == '+') { // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ String attrNumber = attrNumberBuf.toString().trim();
+
+ if (attrNumber.length() == 0) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "nth element $req $ext or $subj expected"));
+ }
+
+ try {
+ mElement = Integer.parseInt(attrNumber) - 1;
+ } catch (NumberFormatException e) {
+
+ if (TYPE_REQ.equals(mType)) {
+ mPrefix = mValue;
+ mValue = attrNumber;
+ } else if (TYPE_EXT.equals(mType)) {
+ mGNType = attrNumber;
+ } else {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "Invalid format in nth element " +
+ "$req $ext or $subj"));
+ }
+
+ // get nth request attribute .
+ if (c == '.') {
+ StringBuffer attrNumberBuf1 = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' &&
+ c != -1 && c != '+') {
+ //System.out.println("mElement read "+
+ // (char)c);
+ attrNumberBuf1.append((char) c);
+ }
+
+ if (c != -1) { // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ }
+ } catch (IOException ex) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", ex.toString()));
+ }
+
+ String attrNumber1 =
+ attrNumberBuf1.toString().trim();
+
+ if (attrNumber1.length() == 0) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "nth element $req or $ext expected"));
+ }
+
+ try {
+ mElement = Integer.parseInt(attrNumber1) - 1;
+ } catch (NumberFormatException ex) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "Invalid format in nth element " +
+ "$req or $ext."));
+ }
+ }
+ }
+ }
+ //System.out.println("----- mElement "+mElement);
+ } else {
+ // value is constant. treat as regular ava.
+ mType = TYPE_CONSTANT;
+
+ // parse ava value.
+ StringBuffer valueBuf = new StringBuffer();
+
+ valueBuf.append((char) c);
+
+ // read forward to get attribute value
+ try {
+ while ((c = in.read()) != ',' && c != -1) {
+ valueBuf.append((char) c);
+ }
+
+ if (c == '+' || c == ',') { // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mValue = valueBuf.toString().trim();
+
+ /* try {
+ * AVA ava = mLdapDNStrConverter.parseAVA(
+ * valueBuf.toString());
+ * mValue = ava.toLdapDNString();
+ * //System.out.println("----- mValue "+mValue);
+ * } catch (IOException e) {
+ * throw new ECompSyntaxErr(e.toString());
+ * }
+ */
+ }
+ }
+
+ public String formAVA(IRequest req,
+ X500Name subject,
+ CertificateExtensions extensions)
+ throws ELdapException {
+ if (TYPE_CONSTANT.equals(mType)) {
+ return mValue;
+ }
+
+ if (TYPE_SUBJ.equals(mType)) {
+ String dn = subject.toString();
+
+ if (mTestDN != null) {
+ dn = mTestDN;
+ }
+
+ //System.out.println("AVAPattern Using dn "+mTestDN);
+ String[] rdns = LDAPDN.explodeDN(dn, false);
+
+ String value = null;
+
+ int nFound = -1;
+
+ for (int i = 0; i < rdns.length; i++) {
+ String[] avas = explodeRDN(rdns[i]);
+
+ for (int j = 0; j < avas.length; j++) {
+ String[] exploded = explodeAVA(avas[j]);
+
+ if (exploded[0].equalsIgnoreCase(mValue) &&
+ ++nFound == mElement) {
+ value = exploded[1];
+ break;
+ }
+ }
+ }
+
+ if (value == null) {
+ return null;
+ }
+
+ return value;
+ }
+
+ if (TYPE_EXT.equals(mType)) {
+
+ if (extensions != null) {
+
+ for (int i = 0; i < extensions.size(); i++) {
+ Extension ext = (Extension)
+ extensions.elementAt(i);
+
+ String extName =
+ OIDMap.getName(ext.getExtensionId());
+
+ int index = extName.lastIndexOf(".");
+
+ if (index != -1) {
+ extName = extName.substring(index + 1);
+ }
+
+ if (extName.equals(mValue)) {
+ // Check the extensions one by one.
+ // For now, just give subjectAltName
+ // as an example.
+ if (mValue.equalsIgnoreCase(
+ SubjectAlternativeNameExtension.NAME)) {
+ try {
+ GeneralNames subjectNames = (GeneralNames)
+ ((SubjectAlternativeNameExtension)
+ ext).get(
+ SubjectAlternativeNameExtension.SUBJECT_NAME);
+
+ if (subjectNames.size() == 0) {
+ break;
+ }
+
+ int j = 0;
+
+ for (Enumeration n =
+ subjectNames.elements();
+ n.hasMoreElements();) {
+
+ GeneralName gn = (GeneralName)
+ n.nextElement();
+
+ String gname = gn.toString();
+
+ index = gname.indexOf(":");
+
+ if (index == -1) {
+ break;
+ }
+
+ String gType =
+ gname.substring(0, index);
+
+ if (mGNType != null) {
+ if (mGNType.equalsIgnoreCase(gType)) {
+ if (mElement == j) {
+ gname =
+ gname.substring(index + 2);
+ return gname;
+ } else {
+ j++;
+ }
+ }
+ } else {
+ if (mElement == j) {
+ gname =
+ gname.substring(index + 2);
+ return gname;
+ }
+ j++;
+ }
+ }
+ } catch (IOException e) {
+ CMS.debug(
+ "AVAPattern: Publishing attr not formed " +
+ "from extension " +
+ "-- no attr : " +
+ mValue);
+ }
+ }
+ }
+ }
+ }
+
+ CMS.debug(
+ "AVAPattern: Publishing:attr not formed " +
+ "from extension " +
+ "-- no attr : " +
+ mValue);
+
+ return null;
+ }
+
+ if (TYPE_REQ.equals(mType)) {
+ // mPrefix and mValue are looked up case-insensitive
+ String reqAttr = req.getExtDataInString(mPrefix, mValue);
+ if (reqAttr == null) {
+ throw new
+ ELdapException(
+ CMS.getUserMessage("CMS_LDAP_NO_REQUEST", mValue, ""));
+ }
+
+ return reqAttr;
+ }
+
+ return null;
+ }
+
+ public String getReqAttr() {
+ if (TYPE_REQ.equals(mType)) {
+ return mValue;
+ } else {
+ return null;
+ }
+ }
+
+ public String getCertAttr() {
+ if (TYPE_SUBJ.equals(mType)) {
+ return mValue;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Explode RDN into AVAs.
+ * Does not handle escaped '+'
+ * Java ldap library does not yet support multiple avas per rdn.
+ * If RDN is malformed returns empty array.
+ */
+ public static String[] explodeRDN(String rdn) {
+ int plus = rdn.indexOf('+');
+
+ if (plus == -1) {
+ return new String[] { rdn };
+ }
+
+ Vector avas = new Vector();
+
+ StringTokenizer token = new StringTokenizer(rdn, "+");
+
+ while (token.hasMoreTokens()) {
+ avas.addElement(token.nextToken());
+ }
+
+ String[] theAvas = new String[avas.size()];
+
+ avas.copyInto(theAvas);
+
+ return theAvas;
+ }
+
+ /**
+ * Explode AVA into name and value.
+ * Does not handle escaped '='
+ * If AVA is malformed empty array is returned.
+ */
+ public static String[] explodeAVA(String ava) {
+ int equals = ava.indexOf('=');
+
+ if (equals == -1) {
+ return null;
+ }
+
+ return new String[] { ava.substring(0, equals).trim(),
+ ava.substring(equals + 1).trim() };
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCaSimpleMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCaSimpleMap.java
new file mode 100644
index 000000000..6bf4ca8d5
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCaSimpleMap.java
@@ -0,0 +1,366 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a request to an entry in the LDAP server.
+ * Takes a dnPattern to form the baseDN from the request attributes
+ * and certificate subject name.Do a base search for the entry
+ * in the directory to publish the cert or crl.
+ * The restriction of this mapper is that the ldap dn components must
+ * be part of certificate subject name or request attributes or constant.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCaSimpleMap implements ILdapMapper, IExtendedPluginInfo {
+ protected static final String PROP_DNPATTERN = "dnPattern";
+ protected static final String PROP_CREATECA = "createCAEntry";
+ protected String mDnPattern = null;
+ protected boolean mCreateCAEntry = true;
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+
+ /* the subject DN pattern */
+ protected MapDNPattern mPattern = null;
+
+ /* the list of request attriubutes to retrieve*/
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attriubutes to retrieve*/
+ protected String[] mCertAttrs = null;
+
+ /* default dn pattern if left blank or not set in the config */
+ public static final String DEFAULT_DNPATTERN =
+ "UID=$req.HTTP_PARAMS.UID, OU=people, O=$subj.o, C=$subj.c";
+
+ /**
+ * Constructor.
+ *
+ * @param dnPattern The base DN.
+ */
+ public LdapCaSimpleMap(String dnPattern) {
+ try {
+ init(dnPattern);
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
+ }
+
+ }
+
+ /**
+ * constructor if initializing from config store.
+ */
+ public LdapCaSimpleMap() {
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String params[] = {
+ "dnPattern;string;Describes how to form the Ldap Subject name in" +
+ " the directory. Example 1: 'uid=CertMgr, o=Fedora'. Example 2:" +
+ " 'uid=$req.HTTP_PARAMS.uid, E=$ext.SubjectAlternativeName.RFC822Name, ou=$subj.ou'. " +
+ "$req means: take the attribute from the request. " +
+ "$subj means: take the attribute from the certificate subject name. " +
+ "$ext means: take the attribute from the certificate extension",
+ "createCAEntry;boolean;If checked, CA entry will be created automatically",
+ IExtendedPluginInfo.HELP_TOKEN + ";configuration-ldappublish-mapper-casimplemapper",
+ IExtendedPluginInfo.HELP_TEXT + ";Describes how to form the LDAP DN of the entry to publish to"
+ };
+
+ return params;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * for initializing from config store.
+ */
+ public void init(IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ String dnPattern = mConfig.getString(PROP_DNPATTERN);
+
+ mCreateCAEntry = mConfig.getBoolean(PROP_CREATECA, true);
+ init(dnPattern);
+ }
+
+ /**
+ * common initialization routine.
+ */
+ protected void init(String dnPattern)
+ throws EBaseException {
+ if (mInited)
+ return;
+
+ mDnPattern = dnPattern;
+ if (mDnPattern == null || mDnPattern.length() == 0)
+ mDnPattern = DEFAULT_DNPATTERN;
+ try {
+ mPattern = new MapDNPattern(mDnPattern);
+ String[] mReqAttrs = mPattern.getReqAttrs();
+ String[] mCertAttrs = mPattern.getCertAttrs();
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_PATTERN_INIT", dnPattern, e.toString()));
+ throw new EBaseException("falied to init with pattern " +
+ dnPattern + " " + e);
+ }
+
+ mInited = true;
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN pattern to form a DN for a LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occured.
+ */
+ public String map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ return map(conn, null, obj);
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN pattern to form a DN for a LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param req the request to map.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occured.
+ */
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+ String dn = null;
+
+ try {
+ dn = formDN(req, obj);
+ if (dn == null) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_NOT_FORMED"));
+ String s1 = "";
+
+ if (req != null)
+ s1 = req.getRequestId().toString();
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_NO_DN_MATCH", s1));
+ }
+ int scope = LDAPv2.SCOPE_BASE;
+ String filter = "(objectclass=*)";
+
+ // search for entry
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "searching for dn: " + dn + " filter:"
+ + filter + " scope: base");
+
+ LDAPSearchResults results =
+ conn.search(dn, scope, filter, attrs, false);
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY", dn,
+ ((req == null) ? "" : req.getRequestId().toString())));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_MORE_THAN_ONE_ENTRY",
+ ((req == null) ? "" : req.getRequestId().toString())));
+ }
+ if (entry != null)
+ return entry.getDN();
+ else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_ENTRY_NOT_FOUND", dn,
+ ((req == null) ? "" : req.getRequestId().toString())));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND",
+ "null entry"));
+ }
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT && mCreateCAEntry) {
+ try {
+ createCAEntry(conn, dn);
+ log(ILogger.LL_INFO, "CA Entry " + dn + " Created");
+ return dn;
+ } catch (LDAPException e1) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", dn, e1.toString()));
+ if (e1.getLDAPResultCode() == LDAPException.CONSTRAINT_VIOLATION) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CA_ENTRY_NOT_CREATED"));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CA_ENTRY_NOT_CREATED1"));
+ }
+ throw new
+ ELdapException(CMS.getUserMessage("CMS_LDAP_CREATE_CA_FAILED", dn));
+ }
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", dn, e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_EXCEPTION_CAUGHT", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ private void createCAEntry(LDAPConnection conn, String dn)
+ throws LDAPException {
+ LDAPAttributeSet attrs = new LDAPAttributeSet();
+ // OID 2.5.6.16
+ String caOc[] = new String[] {"top",
+ "person",
+ "organizationalPerson",
+ "inetOrgPerson"};
+
+ String oOc[] = {"top",
+ "organization"};
+ String oiOc[] = {"top",
+ "organizationalunit"};
+
+ DN dnobj = new DN(dn);
+ String attrval[] = dnobj.explodeDN(true);
+
+ attrs.add(new LDAPAttribute("cn", attrval[0]));
+ attrs.add(new LDAPAttribute("sn", attrval[0]));
+ attrs.add(new LDAPAttribute("objectclass", caOc));
+ LDAPEntry entry = new LDAPEntry(dn, attrs);
+
+ conn.add(entry);
+ }
+
+ /**
+ * form a dn from component in the request and cert subject name
+ * @param req The request
+ * @param obj The certificate or crl
+ */
+ private String formDN(IRequest req, Object obj) throws EBaseException {
+ X500Name subjectDN = null;
+ CertificateExtensions certExt = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+
+ subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+
+ CMS.debug("LdapCaSimpleMap: cert subject dn:" + subjectDN.toString());
+ X509CertInfo info = (X509CertInfo)
+ ((X509CertImpl) cert).get(
+ X509CertImpl.NAME + "." + X509CertImpl.INFO);
+
+ certExt = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ } catch (java.security.cert.CertificateParsingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (java.security.cert.CertificateException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (ClassCastException e) {
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ subjectDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapCaSimpleMap: crl issuer dn: " +
+ subjectDN.toString());
+ }catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_OBJ_NOT_SUPPORTED",
+ ((req == null) ? "" : req.getRequestId().toString())));
+ return null;
+ }
+ }
+ try {
+ String dn = mPattern.formDN(req, subjectDN, certExt);
+
+ return dn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_FORM_DN",
+ ((req == null) ? "" : req.getRequestId().toString()), e.toString()));
+ throw new EBaseException("falied to form dn for request: " +
+ ((req == null) ? "" : req.getRequestId().toString()) + " " + e);
+ }
+ }
+
+ public String getImplName() {
+ return "LdapCaSimpleMap";
+ }
+
+ public String getDescription() {
+ return "LdapCaSimpleMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement(PROP_DNPATTERN + "=");
+ v.addElement(PROP_CREATECA + "=true");
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ try {
+ if (mDnPattern == null) {
+ v.addElement(PROP_DNPATTERN + "=");
+ }else {
+ v.addElement(PROP_DNPATTERN + "=" +
+ mConfig.getString(PROP_DNPATTERN));
+ }
+ v.addElement(PROP_CREATECA + "=" + mConfig.getBoolean(PROP_CREATECA, true));
+ } catch (Exception e) {
+ }
+ return v;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCaSimpleMapper: " + msg);
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertCompsMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertCompsMap.java
new file mode 100644
index 000000000..7a0bc4130
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertCompsMap.java
@@ -0,0 +1,179 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a X509 certificate to a LDAP entry using AVAs in the certificate's
+ * subject name to form the ldap search dn and filter.
+ * Takes a optional root search dn.
+ * The DN comps are used to form a LDAP entry to begin a subtree search.
+ * The filter comps are used to form a search filter for the subtree.
+ * If none of the DN comps matched, baseDN is used for the subtree.
+ * If the baseDN is null and none of the DN comps matched, it is an error.
+ * If none of the DN comps and filter comps matched, it is an error.
+ * If just the filter comps is null, a base search is performed.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCertCompsMap
+ extends LdapDNCompsMap implements ILdapMapper {
+ ILogger mLogger = CMS.getLogger();
+
+ public LdapCertCompsMap() {
+ // need to support baseDN, dnComps, and filterComps
+ // via configuration
+ }
+
+ /**
+ * Constructor.
+ *
+ * The DN comps are used to form a LDAP entry to begin a subtree search.
+ * The filter comps are used to form a search filter for the subtree.
+ * If none of the DN comps matched, baseDN is used for the subtree.
+ * If the baseDN is null and none of the DN comps matched, it is an error.
+ * If none of the DN comps and filter comps matched, it is an error.
+ * If just the filter comps is null, a base search is performed.
+ *
+ * @param baseDN The base DN.
+ * @param dnComps Components to form the LDAP base dn for search.
+ * @param filterComps Components to form the LDAP search filter.
+ */
+ public LdapCertCompsMap(String baseDN, ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ init(baseDN, dnComps, filterComps);
+ }
+
+ public String getImplName() {
+ return "LdapCertCompsMap";
+ }
+
+ public String getDescription() {
+ return "LdapCertCompsMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = super.getDefaultParams();
+
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = super.getInstanceParams();
+
+ return v;
+ }
+
+ /**
+ * constructor using non-standard certificate attribute.
+ */
+ public LdapCertCompsMap(String certAttr, String baseDN,
+ ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ super(certAttr, baseDN, dnComps, filterComps);
+ }
+
+ protected void init(String baseDN, ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ super.init(baseDN, dnComps, filterComps);
+ }
+
+ /**
+ * Maps a certificate to LDAP entry.
+ * Uses DN components and filter components to form a DN and
+ * filter for a LDAP search.
+ * If the formed DN is null the baseDN will be used.
+ * If the formed DN is null and baseDN is null an error is thrown.
+ * If the filter is null a base search is performed.
+ * If both are null an error is thrown.
+ *
+ * @param conn - the LDAP connection.
+ * @param obj - the X509Certificate.
+ */
+ public String
+ map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+ String result = null;
+ // form dn and filter for search.
+ X500Name subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+
+ CMS.debug("LdapCertCompsMap: " + subjectDN.toString());
+
+ byte[] certbytes = cert.getEncoded();
+
+ result = super.map(conn, subjectDN, certbytes);
+ return result;
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_DECODE_CERT", e.toString()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (ClassCastException e) {
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+ String result = null;
+ X500Name issuerDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapCertCompsMap: " + issuerDN.toString());
+
+ byte[] crlbytes = crl.getEncoded();
+
+ result = super.map(conn, issuerDN, crlbytes);
+ return result;
+ } catch (CRLException ex) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_DECODE_CRL", ex.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CRL_FAILED", ex.toString()));
+ } catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_NOT_SUPPORTED_OBJECT"));
+ return null;
+ }
+ }
+ }
+
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return map(conn, obj);
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCertCompsMap: " + msg);
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertExactMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertExactMap.java
new file mode 100644
index 000000000..dde5950bc
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertExactMap.java
@@ -0,0 +1,193 @@
+// --- 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.cms.publish.mappers;
+
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import netscape.security.x509.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a X509 certificate to a LDAP entry by using the subject name
+ * of the certificate as the LDAP entry DN.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCertExactMap implements ILdapMapper, IExtendedPluginInfo {
+ private ILogger mLogger = CMS.getLogger();
+ protected IConfigStore mConfig = null;
+ boolean mInited = false;
+
+ /**
+ * constructs a certificate subject name mapper with search base.
+ */
+ public LdapCertExactMap() {
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited == true)
+ return;
+ mConfig = config;
+ mInited = true;
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-mapper-certexactmapper",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";Literally uses the subject name of the certificate as the DN to publish to"
+ };
+
+ return params;
+ }
+
+ public String getImplName() {
+ return "LdapCertExactMap";
+ }
+
+ public String getDescription() {
+ return "LdapCertExactMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ return v;
+ }
+
+ /**
+ * Finds the entry for the certificate by looking for the cert
+ * subject name in the subject name attribute.
+ *
+ * @param conn - the LDAP connection.
+ * @param obj - the X509Certificate.
+ */
+ public String
+ map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+
+ X500Name subjectDN = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+
+ subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+
+ CMS.debug("LdapCertExactMap: cert subject dn:" + subjectDN.toString());
+ } catch (ClassCastException e) {
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ subjectDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapCertExactMap: crl issuer dn: " +
+ subjectDN.toString());
+ }catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_NOT_SUPPORTED_OBJECT"));
+ return null;
+ }
+ }
+ try {
+ boolean hasCert = false;
+ boolean hasSubjectName = false;
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "Searching for " + subjectDN.toString());
+
+ LDAPSearchResults results =
+ conn.search(subjectDN.toString(), LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", attrs, false);
+
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY", "", subjectDN.toString()));
+ }
+ if (entry != null) {
+ log(ILogger.LL_INFO, "entry found");
+ return entry.getDN();
+ }
+ return null;
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ /*
+ catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_GET_SUBJECT", e.toString()));
+ throw new ELdapException(
+ LdapResources.GET_CERT_SUBJECT_DN_FAILED, e);
+ }
+ catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_DECODE_CERT", e.toString()));
+ throw new ELdapException(
+ LdapResources.GET_DER_ENCODED_CERT_FAILED, e);
+ }
+ */
+ }
+
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return map(conn, obj);
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCertExactMap: " + msg);
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertSubjMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertSubjMap.java
new file mode 100644
index 000000000..6fcebad01
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCertSubjMap.java
@@ -0,0 +1,337 @@
+// --- 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.cms.publish.mappers;
+
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import netscape.security.x509.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a X509 certificate to a LDAP entry by finding an LDAP entry
+ * which has an attribute whose contents are equal to the cert subject name.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCertSubjMap implements ILdapMapper, IExtendedPluginInfo {
+ public static final String LDAP_CERTSUBJNAME_ATTR = "certSubjectName";
+ protected String mSearchBase = null;
+ protected String mCertSubjNameAttr = LDAP_CERTSUBJNAME_ATTR;
+ protected boolean mUseAllEntries = false;
+
+ private ILogger mLogger = CMS.getLogger();
+ protected IConfigStore mConfig = null;
+ boolean mInited = false;
+
+ public LdapCertSubjMap() {
+ // need to setup the mSearchBase via configuration
+ }
+
+ /**
+ * constructs a certificate subject name mapper with search base.
+ * @param searchBase the dn to start searching for the certificate
+ * subject name.
+ */
+ public LdapCertSubjMap(String searchBase) {
+ if (searchBase == null)
+ throw new IllegalArgumentException(
+ "a null argument to constructor " + this.getClass().getName());
+ mSearchBase = searchBase;
+ mInited = true;
+ }
+
+ /**
+ * Constructor using non-ES cert map attribute name.
+ *
+ * @param searchBase entry to start search.
+ * @param certSubjNameAttr attribute for certificate subject names.
+ * @param certAttr attribute to find certificate.
+ */
+ public LdapCertSubjMap(String searchBase,
+ String certSubjNameAttr, String certAttr) {
+ if (searchBase == null ||
+ certSubjNameAttr == null || certAttr == null)
+ throw new IllegalArgumentException(
+ "a null argument to constructor " + this.getClass().getName());
+ mCertSubjNameAttr = certSubjNameAttr;
+ mSearchBase = searchBase;
+ mInited = true;
+ }
+
+ public LdapCertSubjMap(String searchBase,
+ String certSubjNameAttr, String certAttr, boolean useAllEntries) {
+ if (searchBase == null ||
+ certSubjNameAttr == null || certAttr == null)
+ throw new IllegalArgumentException(
+ "a null argument to constructor " + this.getClass().getName());
+ mCertSubjNameAttr = certSubjNameAttr;
+ mSearchBase = searchBase;
+ mUseAllEntries = useAllEntries;
+ mInited = true;
+ }
+
+ public String getImplName() {
+ return "LdapCertSubjMap";
+ }
+
+ public String getDescription() {
+ return "LdapCertSubjMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("certSubjNameAttr=" + mCertSubjNameAttr);
+ v.addElement("searchBase=");
+ v.addElement("useAllEntries=" + mUseAllEntries);
+ return v;
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ "certSubjNameAttr;string;Name of Ldap attribute containing cert subject name",
+ "searchBase;string;Base DN to search from",
+ "useAllEntries;boolean;Use all entries for publishing",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-mapper-certsubjmapper",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin assumes you want to publish to an LDAP entry which has " +
+ "an attribute whose contents are equal to the cert subject name"
+ };
+
+ return params;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ if (mCertSubjNameAttr == null) {
+ v.addElement("certSubjNameAttr=");
+ } else {
+ v.addElement("certSubjNameAttr=" + mCertSubjNameAttr);
+ }
+ if (mSearchBase == null) {
+ v.addElement("searchBase=");
+ } else {
+ v.addElement("searchBase=" + mSearchBase);
+ }
+ v.addElement("useAllEntries=" + mUseAllEntries);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited == true)
+ return;
+ mConfig = config;
+ mCertSubjNameAttr = config.getString("certSubjNameAttr",
+ LDAP_CERTSUBJNAME_ATTR);
+ mSearchBase = config.getString("searchBase");
+ mUseAllEntries = config.getBoolean("useAllEntries", false);
+ mInited = true;
+ }
+
+ /**
+ * Finds the entry for the certificate by looking for the cert
+ * subject name in the subject name attribute.
+ *
+ * @param conn - the LDAP connection.
+ * @param obj - the X509Certificate.
+ */
+ public String
+ map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+ X500Name subjectDN = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+
+ subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+
+ CMS.debug("LdapCertSubjMap: cert subject dn:" + subjectDN.toString());
+ } catch (ClassCastException e) {
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ subjectDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapCertSubjMap: crl issuer dn: " +
+ subjectDN.toString());
+ }catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_NOT_SUPPORTED_OBJECT"));
+ return null;
+ }
+ }
+ try {
+ boolean hasCert = false;
+ boolean hasSubjectName = false;
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "search " + mSearchBase +
+ " (" + mCertSubjNameAttr + "=" + subjectDN + ") " + mCertSubjNameAttr);
+
+ LDAPSearchResults results =
+ conn.search(mSearchBase, LDAPv2.SCOPE_SUB,
+ "(" + mCertSubjNameAttr + "=" + subjectDN + ")", attrs, false);
+
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY", "", subjectDN.toString()));
+ }
+ if (entry != null) {
+ log(ILogger.LL_INFO, "entry found");
+ return entry.getDN();
+ }
+ return null;
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", "LDAPException", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ /*
+ catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_GET_SUBJECT", e.toString()));
+ throw new ELdapException(
+ LdapResources.GET_CERT_SUBJECT_DN_FAILED, e);
+ }
+ catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_DECODE_CERT", e.toString()));
+ throw new ELdapException(
+ LdapResources.GET_DER_ENCODED_CERT_FAILED, e);
+ }
+ */
+ }
+
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return map(conn, obj);
+ }
+
+ public Vector mapAll(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ Vector v = new Vector();
+
+ if (conn == null)
+ return null;
+ X500Name subjectDN = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+ subjectDN = (X500Name) ((X509Certificate) cert).getSubjectDN();
+ CMS.debug("LdapCertSubjMap: cert subject dn:" + subjectDN.toString());
+ } catch (ClassCastException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_NOT_SUPPORTED_OBJECT"));
+ return v;
+ }
+ try {
+ boolean hasCert = false;
+ boolean hasSubjectName = false;
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "search " + mSearchBase +
+ " (" + mCertSubjNameAttr + "=" + subjectDN + ") " + mCertSubjNameAttr);
+
+ LDAPSearchResults results =
+ conn.search(mSearchBase, LDAPv2.SCOPE_SUB,
+ "(" + mCertSubjNameAttr + "=" + subjectDN + ")", attrs, false);
+
+ while (results.hasMoreElements()) {
+ LDAPEntry entry = results.next();
+ String dn = entry.getDN();
+ v.addElement(dn);
+ CMS.debug("LdapCertSubjMap: dn="+dn);
+ }
+ CMS.debug("LdapCertSubjMap: Number of entries: " + v.size());
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", "LDAPException", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ return v;
+ }
+
+ public Vector mapAll(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return mapAll(conn, obj);
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCertSubjMap: " + msg);
+ }
+
+ /**
+ * return search base
+ */
+ public String getSearchBase() {
+ return mSearchBase;
+ }
+
+ /**
+ * return certificate subject attribute
+ */
+ public String getCertSubjNameAttr() {
+ return mCertSubjNameAttr;
+ }
+
+ public boolean useAllEntries() {
+ return mUseAllEntries;
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCrlIssuerCompsMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCrlIssuerCompsMap.java
new file mode 100644
index 000000000..3a55b4ebe
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapCrlIssuerCompsMap.java
@@ -0,0 +1,159 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Default crl mapper.
+ * maps the crl to a ldap entry by using components in the issuer name
+ * to find the CA's entry.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCrlIssuerCompsMap
+ extends LdapDNCompsMap implements ILdapMapper {
+ ILogger mLogger = CMS.getLogger();
+
+ public LdapCrlIssuerCompsMap() {
+ // need to support baseDN, dnComps, and filterComps
+ // via configuration
+ }
+
+ /**
+ * Constructor.
+ *
+ * The DN comps are used to form a LDAP entry to begin a subtree search.
+ * The filter comps are used to form a search filter for the subtree.
+ * If none of the DN comps matched, baseDN is used for the subtree.
+ * If the baseDN is null and none of the DN comps matched, it is an error.
+ * If none of the DN comps and filter comps matched, it is an error.
+ * If just the filter comps is null, a base search is performed.
+ *
+ * @param baseDN The base DN.
+ * @param dnComps Components to form the LDAP base dn for search.
+ * @param filterComps Components to form the LDAP search filter.
+ */
+ public LdapCrlIssuerCompsMap(String baseDN, ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ init(baseDN, dnComps, filterComps);
+ }
+
+ /**
+ * constructor using non-standard certificate attribute.
+ */
+ public LdapCrlIssuerCompsMap(String crlAttr, String baseDN,
+ ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ super(crlAttr, baseDN, dnComps, filterComps);
+ }
+
+ public String getImplName() {
+ return "LdapCrlIssuerCompsMap";
+ }
+
+ public String getDescription() {
+ return "LdapCrlIssuerCompsMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = super.getDefaultParams();
+
+ //v.addElement("crlAttr=" + LdapCrlPublisher.LDAP_CRL_ATTR);
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = super.getInstanceParams();
+
+ return v;
+ }
+
+ protected void init(String baseDN, ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ //mLdapAttr = LdapCrlPublisher.LDAP_CRL_ATTR;
+ super.init(baseDN, dnComps, filterComps);
+ }
+
+ /**
+ * Maps a crl to LDAP entry.
+ * Uses issuer DN components and filter components to form a DN and
+ * filter for a LDAP search.
+ * If the formed DN is null the baseDN will be used.
+ * If the formed DN is null and baseDN is null an error is thrown.
+ * If the filter is null a base search is performed.
+ * If both are null an error is thrown.
+ *
+ * @param conn - the LDAP connection.
+ * @param obj - the X509Certificate.
+ * @return the result. LdapCertMapResult is also used for CRL.
+ */
+ public String
+ map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ try {
+ String result = null;
+ X500Name issuerDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapCrlIssuerCompsMap: " + issuerDN.toString());
+
+ byte[] crlbytes = crl.getEncoded();
+
+ result = super.map(conn, issuerDN, crlbytes);
+ return result;
+ } catch (CRLException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_DECODE_CRL", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CRL_FAILED", e.toString()));
+ }
+ }
+
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return map(conn, obj);
+ }
+
+ /**
+ * overrides super's log().
+ */
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCrlCompsMap: " + msg);
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapDNCompsMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapDNCompsMap.java
new file mode 100644
index 000000000..49fce4994
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapDNCompsMap.java
@@ -0,0 +1,439 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a Subject name to an entry in the LDAP server.
+ * subject name to form the ldap search dn and filter.
+ * Takes a optional root search dn.
+ * The DN comps are used to form a LDAP entry to begin a subtree search.
+ * The filter comps are used to form a search filter for the subtree.
+ * If none of the DN comps matched, baseDN is used for the subtree.
+ * If the baseDN is null and none of the DN comps matched, it is an error.
+ * If none of the DN comps and filter comps matched, it is an error.
+ * If just the filter comps is null, a base search is performed.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapDNCompsMap
+ implements ILdapPlugin, IExtendedPluginInfo {
+ //protected String mLdapAttr = null;
+ protected String mBaseDN = null;
+ protected ObjectIdentifier[] mDnComps = null;
+ protected ObjectIdentifier[] mFilterComps = null;
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+
+ /**
+ * Constructor.
+ *
+ * The DN comps are used to form a LDAP entry to begin a subtree search.
+ * The filter comps are used to form a search filter for the subtree.
+ * If none of the DN comps matched, baseDN is used for the subtree.
+ * If the baseDN is null and none of the DN comps matched, it is an error.
+ * If none of the DN comps and filter comps matched, it is an error.
+ * If just the filter comps is null, a base search is performed.
+ *
+ * @param baseDN The base DN.
+ * @param dnComps Components to form the LDAP base dn for search.
+ * @param filterComps Components to form the LDAP search filter.
+ */
+ public LdapDNCompsMap(String ldapAttr, String baseDN,
+ ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ //mLdapAttr = ldapAttr;
+ init(baseDN, dnComps, filterComps);
+ }
+
+ /**
+ * constructor if initializing from config store.
+ */
+ public LdapDNCompsMap() {
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * for initializing from config store.
+ */
+ public void init(IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ String baseDN = mConfig.getString("baseDN");
+ ObjectIdentifier[] dnComps =
+ getCompsFromString(mConfig.getString("dnComps"));
+ ObjectIdentifier[] filterComps =
+ getCompsFromString(mConfig.getString("filterComps"));
+
+ init(baseDN, dnComps, filterComps);
+ }
+
+ public String getImplName() {
+ return "LdapDNCompsMap";
+ }
+
+ public String getDescription() {
+ return "LdapDNCompsMap";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] s = {
+ "baseDN;string;Base to search from. E.g ou=Engineering,o=Fedora",
+ "dnComps;string;Comma-separated list of attributes to put in the DN",
+ "filterComps;string;Comma-separated list of attributes to form the filter",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-mapper-dncompsmapper",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";More complex mapper. Used when there is not enough information " +
+ "in the cert request to form the complete LDAP DN. Using this " +
+ "plugin, you can specify additional LDAP filters to narrow down the " +
+ "search"
+ };
+
+ return s;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("baseDN=");
+ v.addElement("dnComps=");
+ v.addElement("filterComps=");
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ try {
+ if (mBaseDN == null) {
+ v.addElement("baseDN=");
+ } else {
+ v.addElement("baseDN=" + mConfig.getString("baseDN"));
+ }
+ if (mDnComps == null) {
+ v.addElement("dnComps=");
+ } else {
+ v.addElement("dnComps=" +
+ mConfig.getString("dnComps"));
+ }
+ if (mFilterComps == null) {
+ v.addElement("filterComps=");
+ } else {
+ v.addElement("filterComps=" +
+ mConfig.getString("filterComps"));
+ }
+ } catch (Exception e) {
+ }
+ return v;
+ }
+
+ /**
+ * common initialization routine.
+ */
+ protected void init(String baseDN, ObjectIdentifier[] dnComps,
+ ObjectIdentifier[] filterComps) {
+ if (mInited)
+ return;
+
+ mBaseDN = baseDN;
+ if (dnComps != null)
+ mDnComps = (ObjectIdentifier[]) dnComps.clone();
+ if (filterComps != null)
+ mFilterComps = (ObjectIdentifier[]) filterComps.clone();
+
+ // log debug info.
+ for (int i = 0; i < mDnComps.length; i++) {
+ CMS.debug(
+ "LdapDNCompsMap: dnComp " + X500NameAttrMap.getDefault().getName(mDnComps[i]));
+ }
+ for (int i = 0; i < mFilterComps.length; i++) {
+ CMS.debug("LdapDNCompsMap: filterComp " +
+ X500NameAttrMap.getDefault().getName(mFilterComps[i]));
+ }
+ mInited = true;
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN components and filter components to form a DN and
+ * filter for a LDAP search.
+ * If the formed DN is null the baseDN will be used.
+ * If the formed DN is null and baseDN is null an error is thrown.
+ * If the filter is null a base search is performed.
+ * If both are null an error is thrown.
+ *
+ * @param conn the LDAP connection.
+ * @param x500name the dn to map.
+ * @param obj the object
+ * @exception ELdapException if any LDAP exceptions occured.
+ * @return the DN of the entry.
+ */
+ public String map(LDAPConnection conn, X500Name x500name,
+ byte[] obj)
+ throws ELdapException {
+ try {
+ if (conn == null)
+ return null;
+
+ CMS.debug("LdapDNCompsMap: " + x500name.toString());
+
+ String[] dnAndFilter = formDNandFilter(x500name);
+ String dn = dnAndFilter[0];
+ String filter = dnAndFilter[1];
+
+ if (dn == null) {
+ // #362332
+ // if (filter == null) {
+ // log(ILogger.LL_FAILURE, "No dn and filter formed");
+ // throw new ELdapException(
+ // LdapResources.NO_DN_AND_FILTER_COMPS,
+ // x500name.toString());
+ // }
+ if (mBaseDN == null) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_BASE"));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_NO_DN_COMPS_AND_BASEDN",
+ x500name.toString()));
+ }
+ dn = mBaseDN;
+ }
+ int scope = LDAPv2.SCOPE_SUB;
+
+ if (filter == null) {
+ scope = LDAPv2.SCOPE_BASE;
+ filter = "(objectclass=*)";
+ }
+
+ // search for entry
+ String[] attrs;
+
+ attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "searching for " + dn + " " + filter + " " +
+ ((scope == LDAPv2.SCOPE_SUB) ? "sub" : "base"));
+
+ LDAPSearchResults results =
+ conn.search(dn, scope, filter, attrs, false);
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY", "", x500name.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_MORE_THAN_ONE_ENTRY",
+ x500name.toString()));
+ }
+ if (entry != null) {
+ return entry.getDN();
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_ENTRY_NOT_FOUND", "", x500name.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND",
+ "null entry"));
+ }
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", "LDAPException", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapDNCompsMap: " + msg);
+ }
+
+ /**
+ * form a dn and filter from component in the cert subject name
+ * @param subjName subject name
+ */
+ public String[] formDNandFilter(X500Name subjName)
+ throws ELdapException {
+ Vector dnRdns = new Vector();
+ SearchFilter filter = new SearchFilter();
+ X500NameAttrMap attrMap = X500NameAttrMap.getDefault();
+ String dnStr = null, filterStr = null;
+ ObjectIdentifier EOid = attrMap.getOid("E");
+ ObjectIdentifier mailOid = attrMap.getOid("MAIL");
+
+ try {
+ // get the base DN & filter.
+ for (Enumeration n = subjName.getRDNs(); n.hasMoreElements();) {
+ RDN rdn = (RDN) n.nextElement();
+ // NOTE assumes one AVA per RDN.
+ AVA ava = rdn.getAssertion()[0];
+ ObjectIdentifier oid = ava.getOid();
+
+ for (int i = 0; i < mDnComps.length; i++) {
+ if (mDnComps[i].equals(oid)) {
+ if (oid == EOid) {
+ DerValue val = ava.getValue();
+ AVA newAVA = new AVA(mailOid, val);
+ RDN newRDN = new RDN(new AVA[] { newAVA }
+ );
+
+ CMS.debug(
+ "LdapDNCompsMap: Converted " + rdn.toLdapDNString() + " to " +
+ newRDN.toLdapDNString() + " in DN");
+ rdn = newRDN;
+ }
+ dnRdns.addElement(rdn);
+ CMS.debug(
+ "LdapDNCompsMap: adding dn comp " + rdn.toLdapDNString());
+ break;
+ }
+ }
+ for (int i = 0; i < mFilterComps.length; i++) {
+ if (mFilterComps[i].equals(oid)) {
+ if (oid == EOid) {
+ DerValue val = ava.getValue();
+ AVA newAVA = new AVA(mailOid, val);
+
+ CMS.debug(
+ "LdapDNCompsMap: Converted " + ava.toLdapDNString() + " to " +
+ newAVA.toLdapDNString() + " in filter");
+ ava = newAVA;
+ }
+ filter.addElement(ava.toLdapDNString());
+ CMS.debug(
+ "LdapDNCompsMap: adding filter comp " + ava.toLdapDNString());
+ break;
+ }
+ }
+
+ // XXX should be an error when string is null?
+ // return to caller to decide.
+ if (dnRdns.size() != 0) {
+ dnStr = new X500Name(dnRdns).toLdapDNString();
+ }
+ if (filter.size() != 0) {
+ filterStr = filter.toFilterString();
+ }
+ }
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_FROM_SUBJ_TO_DN", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_FORM_DN_COMPS_FAILED", e.toString()));
+ }
+
+ return new String[] { dnStr, filterStr };
+ }
+
+ public ObjectIdentifier[] getDnComps() {
+ return (ObjectIdentifier[]) mDnComps.clone();
+ }
+
+ public ObjectIdentifier[] getFilterComps() {
+ return (ObjectIdentifier[]) mFilterComps.clone();
+ }
+
+ /**
+ * class for forming search filters for ldap searching from
+ * name=value components. components are anded.
+ */
+ public static class SearchFilter extends Vector {
+ public String toFilterString() {
+ StringBuffer buf = new StringBuffer();
+
+ if (elementCount == 0) {
+ return null;
+ }
+ if (elementCount == 1) {
+ buf.append("(" + (String) elementData[0] + ")");
+ return buf.toString();
+ }
+ buf.append("(&");
+ for (int i = 0; i < elementCount; i++) {
+ buf.append("(" + (String) elementData[i] + ")");
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+ }
+
+ /**
+ * useful routine for parsing components given as string to
+ * arrays of objectidentifiers.
+ * The string is expected to be comma separated AVA attribute names.
+ * For example, "uid,cn,o,ou". Attribute names are case insensitive.
+ * @param val the string specifying the comps
+ * @exception ELdapException if any error occurs.
+ */
+ public static ObjectIdentifier[] getCompsFromString(String val)
+ throws ELdapException {
+ StringTokenizer tokens;
+ ObjectIdentifier[] comps;
+ String attr;
+ ObjectIdentifier oid;
+
+ if (val == null || val.length() == 0)
+ return new ObjectIdentifier[0];
+
+ tokens = new StringTokenizer(val, ", \t\n\r");
+ comps = new ObjectIdentifier[tokens.countTokens()];
+ if (comps.length == 0) {
+ return new ObjectIdentifier[0];
+ }
+ int i = 0;
+
+ while (tokens.hasMoreTokens()) {
+ attr = tokens.nextToken().trim();
+ // mail -> E hack to look for E in subject names.
+ if (attr.equalsIgnoreCase("mail"))
+ attr = "E";
+ oid = X500NameAttrMap.getDefault().getOid(attr);
+ if (oid != null) {
+ comps[i++] = oid;
+ } else {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_UNKNOWN_ATTR_IN_DN_FILTER_COMPS", attr));
+ }
+ }
+ return comps;
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapEnhancedMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapEnhancedMap.java
new file mode 100644
index 000000000..ff445bb5e
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapEnhancedMap.java
@@ -0,0 +1,639 @@
+// --- 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 statement //
+///////////////////////
+
+package com.netscape.cms.publish.mappers;
+
+
+///////////////////////
+// import statements //
+///////////////////////
+
+/* cert server imports */
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+/* LDAP imports */
+import netscape.ldap.*;
+import netscape.ldap.util.*;
+
+/* security imports */
+import netscape.security.util.*;
+import netscape.security.x509.*;
+
+/* java sdk imports */
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.util.*;
+
+
+//////////////////////
+// class definition //
+//////////////////////
+
+/**
+ * Maps a request to an entry in the LDAP server.
+ * Takes a dnPattern to form the baseDN from the
+ * request attributes and certificate subject name.
+ * Does a base search for the entry in the directory
+ * to publish the cert or crl. The restriction of
+ * this mapper is that the ldap dn components must
+ * be part of certificate subject name or request
+ * attributes or constant. The difference of this
+ * mapper and LdapSimpleMap is that if the ldap
+ * entry is not found, it has the option to create
+ * the ldap entry given the dn and attributes
+ * formulated.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapEnhancedMap
+ implements ILdapMapper, IExtendedPluginInfo {
+ ////////////////////////
+ // default parameters //
+ ////////////////////////
+
+
+
+ //////////////////////////////////////
+ // local LdapEnhancedMap parameters //
+ //////////////////////////////////////
+
+ private boolean mInited = false;
+
+ // the subject DN pattern
+ protected MapDNPattern mPattern = null;
+
+ // the list of request attriubutes to retrieve
+ protected String[] mReqAttrs = null;
+
+ // the list of cert attributes to retrieve
+ protected String[] mCertAttrs = null;
+
+ protected String[] mLdapValues = null;
+
+ ////////////////////////////
+ // ILdapMapper parameters //
+ ////////////////////////////
+
+ /* mapper plug-in fields */
+ protected static final String PROP_DNPATTERN = "dnPattern";
+ protected static final String PROP_CREATE = "createEntry";
+ // the object class of the entry to be created. xxxx not done yet
+ protected static final String PROP_OBJCLASS = "objectClass";
+ // req/cert/ext attribute --> directory attribute table
+ protected static final String PROP_ATTRNUM = "attrNum";
+ protected static final String PROP_ATTR_NAME = "attrName";
+ protected static final String PROP_ATTR_PATTERN = "attrPattern";
+
+ /* mapper plug-in fields initialization values */
+ private static final int DEFAULT_NUM_ATTRS = 1;
+
+ /* Holds mapper plug-in fields accepted by this implementation.
+ * This list is passed to the configuration console so configuration
+ * for instances of this implementation can be configured through the
+ * console.
+ */
+ private static Vector defaultParams = new Vector();
+
+ static {
+ defaultParams.addElement(PROP_DNPATTERN + "=");
+ defaultParams.addElement(PROP_CREATE + "=true");
+ defaultParams.addElement(PROP_ATTRNUM + "=" + DEFAULT_NUM_ATTRS);
+ for (int i = 0; i < DEFAULT_NUM_ATTRS; i++) {
+ defaultParams.addElement(PROP_ATTR_NAME + i + "=");
+ defaultParams.addElement(PROP_ATTR_PATTERN + i + "=");
+ }
+ }
+
+ /* mapper plug-in values */
+ protected String mDnPattern = null;
+ protected boolean mCreateEntry = true;
+ private int mNumAttrs = DEFAULT_NUM_ATTRS;
+ protected String[] mLdapNames = null;
+ protected String[] mLdapPatterns = null;
+
+ /* miscellaneous constants local to this mapper plug-in */
+ // default dn pattern if left blank or not set in the config
+ public static final String DEFAULT_DNPATTERN =
+ "UID=$req.HTTP_PARAMS.UID, " +
+ "OU=people, O=$subj.o, C=$subj.c";
+ private static final int MAX_ATTRS = 10;
+ protected static final int DEFAULT_ATTRNUM = 1;
+
+ /* miscellaneous variables local to this mapper plug-in */
+ protected IConfigStore mConfig = null;
+ protected AVAPattern[] mPatterns = null;
+
+ ////////////////////////////////////
+ // IExtendedPluginInfo parameters //
+ ////////////////////////////////////
+
+
+
+ ///////////////////////
+ // Logger parameters //
+ ///////////////////////
+
+ private ILogger mLogger = CMS.getLogger();
+
+ /////////////////////
+ // default methods //
+ /////////////////////
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public LdapEnhancedMap() {
+ }
+
+ ///////////////////////////////////
+ // local LdapEnhancedMap methods //
+ ///////////////////////////////////
+
+ /**
+ * common initialization routine.
+ */
+ protected void init(String dnPattern)
+ throws EBaseException {
+ if (mInited) {
+ return;
+ }
+
+ mDnPattern = dnPattern;
+ if (mDnPattern == null ||
+ mDnPattern.length() == 0) {
+ mDnPattern = DEFAULT_DNPATTERN;
+ }
+
+ try {
+ mPattern = new MapDNPattern(mDnPattern);
+ String[] mReqAttrs = mPattern.getReqAttrs();
+ String[] mCertAttrs = mPattern.getCertAttrs();
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_PATTERN_INIT",
+ dnPattern, e.toString()));
+ throw new EBaseException(
+ "falied to init with pattern " +
+ dnPattern + " " + e);
+ }
+
+ mInited = true;
+ }
+
+ /**
+ * form a dn from component in the request and cert subject name
+ * @param req The request
+ * @param obj The certificate or crl
+ */
+ private String formDN(IRequest req, Object obj)
+ throws EBaseException {
+ CertificateExtensions certExt = null;
+ X500Name subjectDN = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+
+ subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+ CMS.debug(
+ "LdapEnhancedMap: cert subject dn:" +
+ subjectDN.toString());
+
+ //certExt = (CertificateExtensions)
+ // ((X509CertImpl)cert).get(
+ // X509CertInfo.EXTENSIONS);
+ X509CertInfo info = (X509CertInfo)
+ ((X509CertImpl) cert).get(
+ X509CertImpl.NAME +
+ "." +
+ X509CertImpl.INFO);
+
+ certExt = (CertificateExtensions)
+ info.get(CertificateExtensions.NAME);
+ } catch (java.security.cert.CertificateParsingException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (java.security.cert.CertificateException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (ClassCastException e) {
+
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ subjectDN = (X500Name)
+ ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug(
+ "LdapEnhancedMap: crl issuer dn: " +
+
+ subjectDN.toString());
+ } catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_PUBLISH_OBJ_NOT_SUPPORTED",
+ ((req == null) ? ""
+ : req.getRequestId().toString())));
+ return null;
+ }
+ }
+
+ try {
+ mLdapValues = new String[mNumAttrs];
+
+ for (int i = 0; i < mNumAttrs; i++) {
+ if (mPatterns[i] != null) {
+ mLdapValues[i] = mPatterns[i].formAVA(
+ req,
+ subjectDN,
+ certExt);
+ }
+ }
+
+ String dn = mPattern.formDN(req, subjectDN, certExt);
+
+ return dn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_CANT_FORM_DN",
+ ((req == null) ? ""
+ : req.getRequestId().toString()), e.toString()));
+
+ throw new EBaseException(
+ "failed to form dn for request: " +
+ ((req == null) ? ""
+ : req.getRequestId().toString()) +
+ " " + e);
+ }
+ }
+
+ private void createEntry(LDAPConnection conn, String dn)
+ throws LDAPException {
+ LDAPAttributeSet attrs = new LDAPAttributeSet();
+
+ // OID 2.5.6.16
+ String caOc[] = { "top",
+ "person",
+ "organizationalPerson",
+ "inetOrgPerson" };
+
+ DN dnobj = new DN(dn);
+ String attrval[] = dnobj.explodeDN(true);
+
+ attrs.add(new LDAPAttribute("cn", attrval[0]));
+ attrs.add(new LDAPAttribute("sn", attrval[0]));
+ attrs.add(new LDAPAttribute("objectclass", caOc));
+
+ for (int i = 0; i < mNumAttrs; i++) {
+ if (mLdapNames[i] != null &&
+ !mLdapNames[i].trim().equals("") &&
+ mLdapValues[i] != null &&
+ !mLdapValues[i].trim().equals("")) {
+ attrs.add(new LDAPAttribute(mLdapNames[i],
+ mLdapValues[i]));
+ }
+ }
+
+ LDAPEntry entry = new LDAPEntry(dn, attrs);
+
+ conn.add(entry);
+ }
+
+ /////////////////////////
+ // ILdapMapper methods //
+ /////////////////////////
+
+ /**
+ * for initializing from config store.
+ *
+ * implementation for extended
+ * ILdapPlugin interface method
+ */
+ public void init(IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+
+ mDnPattern = mConfig.getString(PROP_DNPATTERN,
+ DEFAULT_DNPATTERN);
+
+ mCreateEntry = mConfig.getBoolean(PROP_CREATE,
+ true);
+
+ mNumAttrs = mConfig.getInteger(PROP_ATTRNUM,
+ 0);
+
+ mLdapNames = new String[mNumAttrs];
+
+ mLdapPatterns = new String[mNumAttrs];
+
+ mPatterns = new AVAPattern[mNumAttrs];
+ for (int i = 0; i < mNumAttrs; i++) {
+ mLdapNames[i] =
+ mConfig.getString(PROP_ATTR_NAME +
+ Integer.toString(i),
+ "");
+
+ mLdapPatterns[i] =
+ mConfig.getString(PROP_ATTR_PATTERN +
+ Integer.toString(i),
+ "");
+
+ if (mLdapPatterns[i] != null &&
+ !mLdapPatterns[i].trim().equals("")) {
+ mPatterns[i] = new AVAPattern(mLdapPatterns[i]);
+ }
+ }
+
+ init(mDnPattern);
+ }
+
+ /**
+ * implementation for extended
+ * ILdapPlugin interface method
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public String getImplName() {
+ return "LdapEnhancedMap";
+ }
+
+ public String getDescription() {
+ return "LdapEnhancedMap";
+ }
+
+ public Vector getDefaultParams() {
+ return defaultParams;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ try {
+ if (mDnPattern == null) {
+ v.addElement(PROP_DNPATTERN + "=");
+ }else {
+ v.addElement(PROP_DNPATTERN + "=" +
+ mConfig.getString(PROP_DNPATTERN));
+ }
+
+ v.addElement(PROP_CREATE + "=" +
+ mConfig.getBoolean(PROP_CREATE,
+ true));
+
+ v.addElement(PROP_ATTRNUM + "=" +
+ mConfig.getInteger(PROP_ATTRNUM,
+ DEFAULT_NUM_ATTRS));
+
+ for (int i = 0; i < mNumAttrs; i++) {
+ if (mLdapNames[i] != null) {
+ v.addElement(PROP_ATTR_NAME + i +
+ "=" + mLdapNames[i]);
+ } else {
+ v.addElement(PROP_ATTR_NAME + i +
+ "=");
+ }
+
+ if (mLdapPatterns[i] != null) {
+ v.addElement(PROP_ATTR_PATTERN + i +
+ "=" + mLdapPatterns[i]);
+ } else {
+ v.addElement(PROP_ATTR_PATTERN + i +
+ "=");
+ }
+ }
+ } catch (Exception e) {
+ }
+
+ return v;
+ }
+
+ /**
+ * Maps an X500 subject name to an LDAP entry.
+ * Uses DN pattern to form a DN for an LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occurred.
+ */
+ public String map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ return map(conn, null, obj);
+ }
+
+ /**
+ * Maps an X500 subject name to an LDAP entry.
+ * Uses DN pattern to form a DN for an LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param req the request to map.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occurred.
+ */
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ if (conn == null) {
+ return null;
+ }
+
+ String dn = null;
+
+ try {
+ dn = formDN(req, obj);
+ if (dn == null) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_NOT_FORMED"));
+
+ String s1 = "";
+
+ if (req != null)
+ s1 = req.getRequestId().toString();
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_NO_DN_MATCH", s1));
+ }
+
+ int scope = LDAPv2.SCOPE_BASE;
+ String filter = "(objectclass=*)";
+
+ // search for entry
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO,
+ "searching for dn: " +
+ dn + " filter:" +
+ filter + " scope: base");
+
+ LDAPSearchResults results = conn.search(dn,
+ scope,
+ filter,
+ attrs,
+ false);
+
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY",
+ dn +
+ ((req == null) ? ""
+ : req.getRequestId().toString())));
+
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_MORE_THAN_ONE_ENTRY",
+ ((req == null) ? ""
+ : req.getRequestId().toString())));
+ }
+
+ if (entry != null) {
+ return entry.getDN();
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_ENTRY_NOT_FOUND",
+ dn +
+ ((req == null) ? ""
+ : req.getRequestId().toString())));
+
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND",
+ "null entry"));
+ }
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else if (e.getLDAPResultCode() ==
+ LDAPException.NO_SUCH_OBJECT && mCreateEntry) {
+
+ try {
+ createEntry(conn, dn);
+
+ log(ILogger.LL_INFO,
+ "Entry " +
+ dn +
+ " Created");
+
+ return dn;
+ } catch (LDAPException e1) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION",
+ dn,
+ e.toString()));
+
+ log(ILogger.LL_FAILURE,
+ "Entry is not created. " +
+ "This may because there are " +
+ "entries in the directory " +
+ "hierachy not exit.");
+
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_CREATE_ENTRY", dn));
+ }
+ } else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION",
+ dn,
+ e.toString()));
+
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_EXCEPTION_CAUGHT",
+ e.toString()));
+
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ /////////////////////////////////
+ // IExtendedPluginInfo methods //
+ /////////////////////////////////
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ Vector v = new Vector();
+
+ v.addElement(PROP_DNPATTERN +
+ ";string;Describes how to form the Ldap " +
+ "Subject name in the directory. " +
+ "Example 1: 'uid=CertMgr, o=Fedora'. " +
+ "Example 2: 'uid=$req.HTTP_PARAMS.uid, " +
+ "E=$ext.SubjectAlternativeName.RFC822Name, " +
+ "ou=$subj.ou'. " +
+ "$req means: take the attribute from the " +
+ "request. " +
+ "$subj means: take the attribute from the " +
+ "certificate subject name. " +
+ "$ext means: take the attribute from the " +
+ "certificate extension");
+ v.addElement(PROP_CREATE +
+ ";boolean;If checked, An entry will be " +
+ "created automatically");
+ v.addElement(PROP_ATTRNUM +
+ ";string;How many attributes to add.");
+ v.addElement(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-mapper-enhancedmapper");
+ v.addElement(IExtendedPluginInfo.HELP_TEXT +
+ ";Describes how to form the LDAP DN of the " +
+ "entry to publish to");
+
+ for (int i = 0; i < MAX_ATTRS; i++) {
+ v.addElement(PROP_ATTR_NAME +
+ Integer.toString(i) +
+ ";string;" +
+ "The name of LDAP attribute " +
+ "to be added. e.g. mail");
+ v.addElement(PROP_ATTR_PATTERN +
+ Integer.toString(i) +
+ ";string;" +
+ "How to create the LDAP attribute value. " +
+ "e.g. $req.HTTP_PARAMS.csrRequestorEmail, " +
+ "$subj.E or " +
+ "$ext.SubjectAlternativeName.RFC822Name");
+ }
+
+ String params[] =
+ com.netscape.cmsutil.util.Utils.getStringArrayFromVector(v);
+
+ return params;
+ }
+
+ ////////////////////
+ // Logger methods //
+ ////////////////////
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapEnhancedMapper: " + msg);
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/LdapSimpleMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapSimpleMap.java
new file mode 100644
index 000000000..6e9e0e74a
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/LdapSimpleMap.java
@@ -0,0 +1,320 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Maps a request to an entry in the LDAP server.
+ * Takes a dnPattern to form the baseDN from the request attributes
+ * and certificate subject name.Do a base search for the entry
+ * in the directory to publish the cert or crl.
+ * The restriction of this mapper is that the ldap dn components must
+ * be part of certificate subject name or request attributes or constant.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapSimpleMap implements ILdapMapper, IExtendedPluginInfo {
+ protected static final String PROP_DNPATTERN = "dnPattern";
+ protected String mDnPattern = null;
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+
+ /* the subject DN pattern */
+ protected MapDNPattern mPattern = null;
+
+ /* the list of request attriubutes to retrieve*/
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attriubutes to retrieve*/
+ protected String[] mCertAttrs = null;
+
+ /* default dn pattern if left blank or not set in the config */
+ public static final String DEFAULT_DNPATTERN =
+ "UID=$req.HTTP_PARAMS.UID, OU=people, O=$subj.o, C=$subj.c";
+
+ /**
+ * Constructor.
+ *
+ * @param dnPattern The base DN.
+ */
+ public LdapSimpleMap(String dnPattern) {
+ try {
+ init(dnPattern);
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString()));
+ }
+
+ }
+
+ /**
+ * constructor if initializing from config store.
+ */
+ public LdapSimpleMap() {
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String params[] = {
+ "dnPattern;string;Describes how to form the Ldap Subject name in" +
+ " the directory. Example 1: 'uid=CertMgr, o=Fedora'. Example 2:" +
+ " 'uid=$req.HTTP_PARAMS.uid, E=$ext.SubjectAlternativeName.RFC822Name, ou=$subj.ou'. " +
+ "$req means: take the attribute from the request. " +
+ "$subj means: take the attribute from the certificate subject name. " +
+ "$ext means: take the attribute from the certificate extension",
+ IExtendedPluginInfo.HELP_TOKEN + ";configuration-ldappublish-mapper-simplemapper",
+ IExtendedPluginInfo.HELP_TEXT + ";Describes how to form the LDAP DN of the entry to publish to"
+ };
+
+ return params;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * for initializing from config store.
+ */
+ public void init(IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ String dnPattern = mConfig.getString(PROP_DNPATTERN);
+
+ init(dnPattern);
+ }
+
+ /**
+ * common initialization routine.
+ */
+ protected void init(String dnPattern)
+ throws EBaseException {
+ if (mInited)
+ return;
+
+ mDnPattern = dnPattern;
+ if (mDnPattern == null || mDnPattern.length() == 0)
+ mDnPattern = DEFAULT_DNPATTERN;
+ try {
+ mPattern = new MapDNPattern(mDnPattern);
+ String[] mReqAttrs = mPattern.getReqAttrs();
+ String[] mCertAttrs = mPattern.getCertAttrs();
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_PATTERN_INIT",
+ dnPattern, e.toString()));
+ throw new EBaseException("falied to init with pattern " +
+ dnPattern + " " + e);
+ }
+
+ mInited = true;
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN pattern to form a DN for a LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occured.
+ */
+ public String map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ return map(conn, null, obj);
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN pattern to form a DN for a LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param req the request to map.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occured.
+ */
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ if (conn == null)
+ return null;
+ String dn = null;
+
+ try {
+ dn = formDN(req, obj);
+ if (dn == null) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_NOT_FORMED"));
+ String s1 = "";
+
+ if (req != null)
+ s1 = req.getRequestId().toString();
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_NO_DN_MATCH", s1));
+ }
+ int scope = LDAPv2.SCOPE_BASE;
+ String filter = "(objectclass=*)";
+
+ // search for entry
+ String[] attrs = new String[] { LDAPv3.NO_ATTRS };
+
+ log(ILogger.LL_INFO, "searching for dn: " + dn + " filter:"
+ + filter + " scope: base");
+
+ LDAPSearchResults results =
+ conn.search(dn, scope, filter, attrs, false);
+ LDAPEntry entry = results.next();
+
+ if (results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_MORE_THAN_ONE_ENTRY", dn, ((req == null) ? "" : req.getRequestId().toString())));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_MORE_THAN_ONE_ENTRY",
+ ((req == null) ? "" : req.getRequestId().toString())));
+ }
+ if (entry != null)
+ return entry.getDN();
+ else {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_ENTRY_NOT_FOUND", dn, ((req == null) ? "" : req.getRequestId().toString())));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND",
+ "null entry"));
+ }
+ } catch (ELdapException e) {
+ throw e;
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_DN_MAP_EXCEPTION", "", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ } catch (EBaseException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_EXCEPTION_CAUGHT", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_NO_MATCH_FOUND", e.toString()));
+ }
+ }
+
+ /**
+ * form a dn from component in the request and cert subject name
+ * @param req The request
+ * @param obj The certificate or crl
+ */
+ private String formDN(IRequest req, Object obj) throws
+ EBaseException, ELdapException {
+ X500Name subjectDN = null;
+ CertificateExtensions certExt = null;
+
+ try {
+ X509Certificate cert = (X509Certificate) obj;
+
+ subjectDN =
+ (X500Name) ((X509Certificate) cert).getSubjectDN();
+
+ CMS.debug("LdapSimpleMap: cert subject dn:" + subjectDN.toString());
+ //certExt = (CertificateExtensions)
+ // ((X509CertImpl)cert).get(X509CertInfo.EXTENSIONS);
+ X509CertInfo info = (X509CertInfo)
+ ((X509CertImpl) cert).get(
+ X509CertImpl.NAME + "." + X509CertImpl.INFO);
+
+ certExt = (CertificateExtensions) info.get(
+ CertificateExtensions.NAME);
+ } catch (java.security.cert.CertificateParsingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (java.security.cert.CertificateException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_GET_EXT", e.toString()));
+ } catch (ClassCastException e) {
+ try {
+ X509CRLImpl crl = (X509CRLImpl) obj;
+
+ subjectDN =
+ (X500Name) ((X509CRLImpl) crl).getIssuerDN();
+
+ CMS.debug("LdapSimpleMap: crl issuer dn: " +
+ subjectDN.toString());
+ }catch (ClassCastException ex) {
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_PUBLISH_OBJ_NOT_SUPPORTED",
+ ((req == null) ? "" : req.getRequestId().toString())));
+ return null;
+ }
+ }
+ try {
+ String dn = mPattern.formDN(req, subjectDN, certExt);
+
+ return dn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_FORM_DN",
+ ((req == null) ? "" : req.getRequestId().toString()), e.toString()));
+ throw e;
+ }
+ }
+
+ public String getImplName() {
+ return "LdapSimpleMap";
+ }
+
+ public String getDescription() {
+ return "LdapSimpleMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement(PROP_DNPATTERN + "=");
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ try {
+ if (mDnPattern == null) {
+ v.addElement(PROP_DNPATTERN + "=");
+ }else {
+ v.addElement(PROP_DNPATTERN + "=" +
+ mConfig.getString(PROP_DNPATTERN));
+ }
+ } catch (Exception e) {
+ }
+ return v;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapSimpleMapper: " + msg);
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/MapAVAPattern.java b/pki/base/common/src/com/netscape/cms/publish/mappers/MapAVAPattern.java
new file mode 100644
index 000000000..129c12659
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/MapAVAPattern.java
@@ -0,0 +1,634 @@
+// --- 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.cms.publish.mappers;
+
+
+import java.util.*;
+import com.netscape.certsrv.logging.*;
+import java.io.*;
+import java.security.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a ldap dn from
+ * request attributes and cert subject name.<p>
+ *
+ * dnpattern is a string representing a ldap dn pattern to formulate from
+ * the certificate subject name attributes and request attributes .
+ * If empty or not set, the certificate subject name
+ * will be used as the ldap dn. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$subj" "." attrName [ "." attrNumber ] |
+ * name "=" "$ext" "." extName [ "." nameType ] [ "." attrNumber ]
+ * name "=" "$req" "." attrName [ "." attrNumber ] |
+ * "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>cn=Certificate Manager,ou=people,o=mcom.com</i>
+ * cert subject name: dn: CN=Certificate Manager, OU=people, O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * CN=Certificate Manager, OU=people, O=mcom.com
+ * <p>
+ * note: Subordinate ca enrollment will use ca mapper. Use predicate
+ * to distinguish the ca itself and the subordinates.
+ *
+ * Example2: <i>UID=$req.HTTP_PARAMS.uid, OU=$subj.ou, OU=people, , O=mcom.com</i>
+ * cert subject name: dn: UID=jjames, OU=IS, OU=people, , O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * UID=jjames, OU=IS, OU=people, O=mcom.com
+ * <p>
+ * UID = the 'uid' attribute value in the request. <br>
+ * OU = the 'ou' value in the cert subject name. <br>
+ * O = the string mcom.com. <br>
+ * <p>
+ * Example3: <i>UID=$req.HTTP_PARAMS.uid, E=$ext.SubjectAlternativeName.RFC822Name.1, O=mcom.com</i>
+ * cert subject name: dn: UID=jjames, OU=IS, OU=people, O=mcom.com
+ * cert subjectAltName is rfc822Name: jjames@mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * UID=jjames, E=jjames@mcom.com, O=mcom.com
+ * <p>
+ * UID = the 'uid' attribute value in the request. <br>
+ * E = The first rfc822name value in the subjAltName extension. <br>
+ * O = the string mcom.com. <br>
+ * <p>
+ * </pre>
+ * If an request attribute or subject DN component does not exist,
+ * the attribute is skipped. There is potential risk that a wrong dn
+ * will be mapped into.
+ *
+ * @version $Revision$, $Date$
+ */
+class MapAVAPattern {
+
+ /* the value type of the dn component */
+ public static final String TYPE_REQ = "$req";
+ public static final String TYPE_SUBJ = "$subj";
+ public static final String TYPE_EXT = "$ext";
+ public static final String TYPE_RDN = "$rdn";
+ public static final String TYPE_CONSTANT = "constant";
+
+ public static final String[] GENERAL_NAME_TYPE = { "ANY",
+ "RFC822Name",
+ "DNSName",
+ "X400Name",
+ "DIRECTORYName",
+ "EDIName",
+ "URIName",
+ "IPAddress",
+ "OIDName"};
+ private static final char[] endChars = new char[] { '+', ',' };
+
+ private static final LdapV3DNStrConverter mLdapDNStrConverter =
+ new LdapV3DNStrConverter();
+
+ /* the list of request attributes needed by this AVA */
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attributes needed by this AVA*/
+ protected String[] mCertAttrs = null;
+
+ /* value type */
+ protected String mType = null;
+
+ /* the attribute in the AVA pair */
+ protected String mAttr = null;
+
+ /* value - could be name of a request attribute or
+ * cert subject dn attribute. */
+ protected String mValue = null;
+
+ /* value type - general name type of an extension attribute if any. */
+ protected String mGNType = null;
+
+ /* prefix - prefix of a request attribute if any. */
+ protected String mPrefix = null;
+
+ /* nth value of the ldap or dn attribute */
+ protected int mElement = 0;
+
+ protected String mTestDN = null;
+
+ public MapAVAPattern(String component)
+ throws ELdapException {
+ if (component == null || component.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", component));
+ parse(new PushbackReader(new StringReader(component)));
+ }
+
+ public MapAVAPattern(PushbackReader in)
+ throws ELdapException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws ELdapException {
+ int c;
+
+ // mark ava beginning.
+
+ // skip spaces
+ //System.out.println("============ AVAPattern Begin ===========");
+ //System.out.println("skip spaces");
+
+ try {
+ while ((c = in.read()) == ' ' || c == '\t') {//System.out.println("spaces read "+(char)c);
+ ;
+ }
+ } catch (IOException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "All blank"));
+ }
+ if (c == -1)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "All blank"));
+
+ // $rdn "." number syntax.
+
+ if (c == '$') {
+ //System.out.println("$rdn syntax");
+ mType = TYPE_RDN;
+ try {
+ if (in.read() != 'r' ||
+ in.read() != 'd' ||
+ in.read() != 'n' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "Invalid $ syntax, expecting $rdn"));
+ } catch (IOException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "Invalid $ syntax, expecting $rdn"));
+ }
+
+ StringBuffer rdnNumberBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' && c != -1 && c != '+') {
+ //System.out.println("rdnNumber read "+(char)c);
+ rdnNumberBuf.append((char) c);
+ }
+ if (c != -1) // either ',' or '+'
+ in.unread(c);
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ String rdnNumber = rdnNumberBuf.toString().trim();
+
+ if (rdnNumber.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "$rdn number not set in ava pattern"));
+ try {
+ mElement = Integer.parseInt(rdnNumber) - 1;
+ } catch (NumberFormatException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "Invalid $rdn number in ava pattern"));
+ }
+ return;
+ }
+
+ // name "=" ... syntax.
+
+ // read name
+ //System.out.println("reading name");
+
+ StringBuffer attrBuf = new StringBuffer();
+
+ try {
+ while (c != '=' && c != -1 && c != ',' && c != '+') {
+ attrBuf.append((char) c);
+ c = in.read();
+ //System.out.println("name read "+(char)c);
+ }
+ if (c == ',' || c == '+')
+ in.unread(c);
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ if (c != '=')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "Missing \"=\" in ava pattern"));
+
+ // read value
+ //System.out.println("reading value");
+
+ // skip spaces
+ //System.out.println("skip spaces for value");
+ try {
+ while ((c = in.read()) == ' ' || c == '\t') {//System.out.println("spaces2 read "+(char)c);
+ ;
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ if (c == -1)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "no value after = in ava pattern"));
+
+ if (c == '$') {
+ // check for $subj $ext or $req
+ try {
+ c = in.read();
+ //System.out.println("check $dn or $attr read "+(char)c);
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ if (c == -1)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $subj or $req in ava pattern"));
+ if (c == 'r') {
+ try {
+ if (in.read() != 'e' ||
+ in.read() != 'q' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $req in ava pattern"));
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ mType = TYPE_REQ;
+ //System.out.println("---- mtype $req");
+ } else if (c == 's') {
+ try {
+ if (in.read() != 'u' ||
+ in.read() != 'b' ||
+ in.read() != 'j' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $subj in ava pattern"));
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ mType = TYPE_SUBJ;
+ //System.out.println("----- mtype $subj");
+ } else if (c == 'e') {
+ try {
+ if (in.read() != 'x' ||
+ in.read() != 't' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $ext in ava pattern"));
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ mType = TYPE_EXT;
+ //System.out.println("----- mtype $ext");
+ } else {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "unknown keyword. expecting $subj $ext or $req."));
+ }
+
+ // get request attr name of subject dn pattern from above.
+ String attrName = attrBuf.toString().trim();
+
+ //System.out.println("----- attrName "+attrName);
+ if (attrName.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", "attribute name expected"));
+ mAttr = attrName;
+
+ /*
+ try {
+ ObjectIdentifier attrOid =
+ mLdapDNStrConverter.parseAVAKeyword(attrName);
+ mAttr = mLdapDNStrConverter.encodeOID(attrOid);
+ //System.out.println("----- mAttr "+mAttr);
+ }
+ catch (IOException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", e.toString()));
+ }
+ */
+
+ // get request attribute or cert subject dn attribute
+
+ StringBuffer valueBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' &&
+ c != -1 && c != '.' && c != '+') {
+ //System.out.println("mValue read "+(char)c);
+ valueBuf.append((char) c);
+ }
+ if (c == '+' || c == ',') // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+
+ mValue = valueBuf.toString().trim();
+ if (mValue.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "$subj or $req attribute name expected"));
+ //System.out.println("----- mValue "+mValue);
+
+ // get nth dn xxx not nth request attribute .
+ if (c == '.') {
+ StringBuffer attrNumberBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' && c != -1 && c != '.'
+ && c != '+') {
+ //System.out.println("mElement read "+(char)c);
+ attrNumberBuf.append((char) c);
+ }
+ if (c == ',' || c == '+') // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ String attrNumber = attrNumberBuf.toString().trim();
+
+ if (attrNumber.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "nth element $req $ext or $subj expected"));
+ try {
+ mElement = Integer.parseInt(attrNumber) - 1;
+ } catch (NumberFormatException e) {
+ if (TYPE_REQ.equals(mType)) {
+ mPrefix = mValue;
+ mValue = attrNumber;
+ } else if (TYPE_EXT.equals(mType)) {
+ mGNType = attrNumber;
+ } else
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "Invalid format in nth element $req $ext or $subj"));
+
+ // get nth request attribute .
+ if (c == '.') {
+ StringBuffer attrNumberBuf1 = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' && c != -1 && c != '+') {
+ //System.out.println("mElement read "+(char)c);
+ attrNumberBuf1.append((char) c);
+ }
+ if (c != -1) // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ } catch (IOException ex) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", ex.toString()));
+ }
+ String attrNumber1 = attrNumberBuf1.toString().trim();
+
+ if (attrNumber1.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "nth element $req expected"));
+ try {
+ mElement = Integer.parseInt(attrNumber1) - 1;
+ } catch (NumberFormatException ex) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "Invalid format in nth element $req."));
+
+ }
+ }
+ }
+ }
+ //System.out.println("----- mElement "+mElement);
+ } else {
+ // value is constant. treat as regular ava.
+ mType = TYPE_CONSTANT;
+ //System.out.println("----- mType constant");
+ // parse ava value.
+ StringBuffer valueBuf = new StringBuffer();
+
+ valueBuf.append((char) c);
+ // read forward to get attribute value
+ try {
+ while ((c = in.read()) != ',' &&
+ c != -1) {
+ valueBuf.append((char) c);
+ }
+ if (c == '+' || c == ',') { // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ }
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ try {
+ AVA ava = mLdapDNStrConverter.parseAVA(attrBuf + "=" + valueBuf);
+
+ mValue = ava.toLdapDNString();
+ //System.out.println("----- mValue "+mValue);
+ } catch (IOException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", e.toString()));
+ }
+ }
+ }
+
+ public String formAVA(IRequest req, X500Name subject, CertificateExtensions extensions)
+ throws ELdapException {
+ if (TYPE_CONSTANT.equals(mType))
+ return mValue;
+
+ if (TYPE_RDN.equals(mType)) {
+ String dn = subject.toString();
+
+ if (mTestDN != null)
+ dn = mTestDN;
+ //System.out.println("AVAPattern Using dn "+mTestDN);
+ String[] rdns = LDAPDN.explodeDN(dn, false);
+
+ if (mElement >= rdns.length)
+ return null;
+ return rdns[mElement];
+ }
+
+ if (TYPE_SUBJ.equals(mType)) {
+ String dn = subject.toString();
+
+ if (mTestDN != null)
+ dn = mTestDN;
+ //System.out.println("AVAPattern Using dn "+mTestDN);
+ String[] rdns = LDAPDN.explodeDN(dn, false);
+ String value = null;
+ int nFound = -1;
+
+ for (int i = 0; i < rdns.length; i++) {
+ String[] avas = explodeRDN(rdns[i]);
+
+ for (int j = 0; j < avas.length; j++) {
+ String[] exploded = explodeAVA(avas[j]);
+
+ if (exploded[0].equalsIgnoreCase(mValue) &&
+ ++nFound == mElement) {
+ value = exploded[1];
+ break;
+ }
+ }
+ }
+ if (value == null) {
+ CMS.debug(
+ "MapAVAPattern: attr " + mAttr +
+ " not formed from: cert subject " +
+ dn +
+ "-- no subject component : " + mValue);
+ return null;
+ }
+ return mAttr + "=" + value;
+ }
+
+ if (TYPE_EXT.equals(mType)) {
+ if (extensions != null) {
+ for (int i = 0; i < extensions.size(); i++) {
+ Extension ext = (Extension)
+ extensions.elementAt(i);
+ String extName = OIDMap.getName(ext.getExtensionId());
+ int index = extName.lastIndexOf(".");
+
+ if (index != -1)
+ extName = extName.substring(index + 1);
+ if (
+ extName.equals(mValue)) {
+ // Check the extensions one by one.
+ // For now, just give subjectAltName as an example.
+ if
+ (mValue.equalsIgnoreCase(SubjectAlternativeNameExtension.NAME)) {
+ try {
+ GeneralNames subjectNames = (GeneralNames)
+ ((SubjectAlternativeNameExtension) ext).get(SubjectAlternativeNameExtension.SUBJECT_NAME);
+
+ if (subjectNames.size() == 0)
+ break;
+ int j = 0;
+
+ for (Enumeration n = subjectNames.elements(); n.hasMoreElements();) {
+ GeneralName gn = (GeneralName) n.nextElement();
+ String gname = gn.toString();
+
+ index = gname.indexOf(":");
+ if (index == -1) break;
+ String gType = gname.substring(0, index);
+
+ if (mGNType != null) {
+ if (mGNType.equalsIgnoreCase(gType)) {
+ if (mElement == j) {
+ gname =
+ gname.substring(index + 2);
+ return mAttr + "=" + gname;
+ } else {
+ j++;
+ }
+ }
+ } else {
+ if (mElement == j) {
+ gname =
+ gname.substring(index + 2);
+ return mAttr + "=" + gname;
+ }
+ j++;
+ }
+ }
+ } catch (IOException e) {
+ CMS.debug(
+ "MapAVAPattern: Publishing attr not formed from extension." +
+ "-- no attr : " + mValue);
+ }
+ }
+ }
+ }
+ }
+ CMS.debug(
+ "MapAVAPattern: Publishing:attr not formed from extension " +
+ "-- no attr : " + mValue);
+
+ return null;
+ }
+
+ if (TYPE_REQ.equals(mType)) {
+ // mPrefix and mValue are looked up case-insensitive
+ String reqAttr = req.getExtDataInString(mPrefix, mValue);
+ if (reqAttr == null) {
+ throw new
+ ELdapException(CMS.getUserMessage("CMS_LDAP_NO_REQUEST",
+ mValue, mAttr));
+ }
+ return mAttr + "=" + reqAttr;
+ }
+
+ return null;
+ }
+
+ public String getReqAttr() {
+ if (TYPE_REQ.equals(mType))
+ return mValue;
+ else
+ return null;
+ }
+
+ public String getCertAttr() {
+ if (TYPE_SUBJ.equals(mType))
+ return mValue;
+ else
+ return null;
+ }
+
+ /**
+ * Explode RDN into AVAs.
+ * Does not handle escaped '+'
+ * Java ldap library does not yet support multiple avas per rdn.
+ * If RDN is malformed returns empty array.
+ */
+ public static String[] explodeRDN(String rdn) {
+ int plus = rdn.indexOf('+');
+
+ if (plus == -1)
+ return new String[] { rdn };
+ Vector avas = new Vector();
+ StringTokenizer token = new StringTokenizer(rdn, "+");
+
+ while (token.hasMoreTokens())
+ avas.addElement(token.nextToken());
+ String[] theAvas = new String[avas.size()];
+
+ avas.copyInto(theAvas);
+ return theAvas;
+ }
+
+ /**
+ * Explode AVA into name and value.
+ * Does not handle escaped '='
+ * If AVA is malformed empty array is returned.
+ */
+ public static String[] explodeAVA(String ava) {
+ int equals = ava.indexOf('=');
+
+ if (equals == -1)
+ return null;
+ return new String[] {
+ ava.substring(0, equals).trim(), ava.substring(equals + 1).trim()};
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/MapDNPattern.java b/pki/base/common/src/com/netscape/cms/publish/mappers/MapDNPattern.java
new file mode 100644
index 000000000..2785cc6cd
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/MapDNPattern.java
@@ -0,0 +1,202 @@
+// --- 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.cms.publish.mappers;
+
+
+import com.netscape.certsrv.logging.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a ldap dn from
+ * request attributes and cert subject name.<p>
+ *
+ * dnpattern is a string representing a ldap dn pattern to formulate from
+ * the certificate subject name attributes and request attributes .
+ * If empty or not set, the certificate subject name
+ * will be used as the ldap dn. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$subj" "." attrName [ "." attrNumber ] |
+ * name "=" "$req" "." attrName [ "." attrNumber ] |
+ * "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>cn=Certificate Manager,ou=people,o=mcom.com</i>
+ * cert subject name: dn: CN=Certificate Manager, OU=people, O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * CN=Certificate Manager, OU=people, O=mcom.com
+ * <p>
+ * note: Subordinate ca enrollment will use ca mapper. Use predicate
+ * to distinguish the ca itself and the subordinates.
+ *
+ * Example2: <i>UID=$req.HTTP_PARAMS.uid, OU=$subj.ou, O=people, , O=mcom.com</i>
+ * cert subject name: dn: UID=jjames, OU=IS, O=people, , O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * UID=jjames, OU=IS, OU=people, O=mcom.com
+ * <p>
+ * UID = the 'uid' attribute value in the request. <br>
+ * OU = the 'ou' value in the cert subject name. <br>
+ * O = the string people, mcom.com. <br>
+ * <p>
+ * </pre>
+ * If an request attribute or subject DN component does not exist,
+ * the attribute is skipped. There is potential risk that a wrong dn
+ * will be mapped into.
+ *
+ * @version $Revision$, $Date$
+ */
+public class MapDNPattern {
+
+ /* the list of request attriubutes to retrieve*/
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attriubutes to retrieve*/
+ protected String[] mCertAttrs = null;
+
+ /* rdn patterns */
+ protected MapRDNPattern[] mRDNPatterns = null;
+
+ /* original pattern string */
+ protected String mPatternString = null;
+
+ protected String mTestDN = null;
+
+ /**
+ * Construct a DN pattern by parsing a pattern string.
+ * @param pattern the DN pattern
+ * @exception EBaseException If parsing error occurs.
+ */
+ public MapDNPattern(String pattern)
+ throws ELdapException {
+ if (pattern == null || pattern.equals("")) {
+ CMS.debug(
+ "MapDNPattern: null pattern");
+ } else {
+ mPatternString = pattern;
+ PushbackReader in = new PushbackReader(new StringReader(pattern));
+
+ parse(in);
+ }
+ }
+
+ public MapDNPattern(PushbackReader in)
+ throws ELdapException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws ELdapException {
+ Vector rdnPatterns = new Vector();
+ MapRDNPattern rdnPattern = null;
+ int lastChar = -1;
+
+ do {
+ rdnPattern = new MapRDNPattern(in);
+ rdnPatterns.addElement(rdnPattern);
+ try {
+ lastChar = in.read();
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ }
+ while (lastChar == ',');
+
+ mRDNPatterns = new MapRDNPattern[rdnPatterns.size()];
+ rdnPatterns.copyInto(mRDNPatterns);
+
+ Vector reqAttrs = new Vector();
+
+ for (int i = 0; i < mRDNPatterns.length; i++) {
+ String[] rdnAttrs = mRDNPatterns[i].getReqAttrs();
+
+ if (rdnAttrs != null && rdnAttrs.length > 0)
+ for (int j = 0; j < rdnAttrs.length; j++)
+ reqAttrs.addElement(rdnAttrs[j]);
+ }
+ mReqAttrs = new String[reqAttrs.size()];
+ reqAttrs.copyInto(mReqAttrs);
+
+ Vector certAttrs = new Vector();
+
+ for (int i = 0; i < mRDNPatterns.length; i++) {
+ String[] rdnAttrs = mRDNPatterns[i].getCertAttrs();
+
+ if (rdnAttrs != null && rdnAttrs.length > 0)
+ for (int j = 0; j < rdnAttrs.length; j++)
+ certAttrs.addElement(rdnAttrs[j]);
+ }
+ mCertAttrs = new String[certAttrs.size()];
+ certAttrs.copyInto(mCertAttrs);
+ }
+
+ /**
+ * Form a Ldap v3 DN string from a request and a cert subject name.
+ * @param req the request for (un)publish
+ * @param subject the subjectDN of the certificate
+ * @return Ldap v3 DN string to use for base ldap search.
+ */
+ public String formDN(IRequest req, X500Name subject, CertificateExtensions ext)
+ throws ELdapException {
+ StringBuffer formedDN = new StringBuffer();
+
+ for (int i = 0; i < mRDNPatterns.length; i++) {
+ if (mTestDN != null)
+ mRDNPatterns[i].mTestDN = mTestDN;
+ String rdn = mRDNPatterns[i].formRDN(req, subject, ext);
+
+ if (rdn != null && rdn.length() != 0) {
+ if (formedDN.length() != 0)
+ formedDN.append(",");
+ formedDN.append(rdn);
+ } else {
+ throw new ELdapException("pattern not matched");
+ }
+ }
+ return formedDN.toString();
+ }
+
+ public String[] getReqAttrs() {
+ return (String[]) mReqAttrs.clone();
+ }
+
+ public String[] getCertAttrs() {
+ return (String[]) mCertAttrs.clone();
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/MapRDNPattern.java b/pki/base/common/src/com/netscape/cms/publish/mappers/MapRDNPattern.java
new file mode 100644
index 000000000..e26252dda
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/MapRDNPattern.java
@@ -0,0 +1,218 @@
+// --- 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.cms.publish.mappers;
+
+
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.logging.*;
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a ldap dn from
+ * request attributes and cert subject name.<p>
+ *
+ * dnpattern is a string representing a ldap dn pattern to formulate from
+ * the certificate subject name attributes and request attributes .
+ * If empty or not set, the certificate subject name
+ * will be used as the ldap dn. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$subj" "." attrName [ "." attrNumber ] |
+ * name "=" "$req" "." attrName [ "." attrNumber ] |
+ * "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>cn=Certificate Manager,ou=people,o=mcom.com</i>
+ * cert subject name: dn: CN=Certificate Manager, OU=people, O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * CN=Certificate Manager, OU=people, O=mcom.com
+ * <p>
+ * note: Subordinate ca enrollment will use ca mapper. Use predicate
+ * to distinguish the ca itself and the subordinates.
+ *
+ * Example2: <i>UID=$req.HTTP_PARAMS.uid, OU=$subj.ou, O=people, , O=mcom.com</i>
+ * cert subject name: dn: UID=jjames, OU=IS, O=people, , O=mcom.com
+ * request attributes: uid: cmanager
+ * <p>
+ * The dn formulated will be : <br>
+ * UID=jjames, OU=IS, OU=people, O=mcom.com
+ * <p>
+ * UID = the 'uid' attribute value in the request. <br>
+ * OU = the 'ou' value in the cert subject name. <br>
+ * O = the string people, mcom.com. <br>
+ * <p>
+ * </pre>
+ * If an request attribute or subject DN component does not exist,
+ * the attribute is skipped.There is potential risk that a wrong dn
+ * will be mapped into.
+ *
+ * @version $Revision$, $Date$
+ */
+class MapRDNPattern {
+
+ /* the list of request attributes needed by this RDN */
+ protected String[] mReqAttrs = null;
+
+ /* the list of cert attributes needed by this RDN */
+ protected String[] mCertAttrs = null;
+
+ /* AVA patterns */
+ protected MapAVAPattern[] mAVAPatterns = null;
+
+ /* original pattern string */
+ protected String mPatternString = null;
+
+ protected String mTestDN = null;
+
+ /**
+ * Construct a DN pattern by parsing a pattern string.
+ * @param pattenr the DN pattern
+ * @exception ELdapException If parsing error occurs.
+ */
+ public MapRDNPattern(String pattern)
+ throws ELdapException {
+ if (pattern == null || pattern.equals("")) {
+ CMS.debug(
+ "MapDNPattern: null pattern");
+ } else {
+ mPatternString = pattern;
+ PushbackReader in = new PushbackReader(new StringReader(pattern));
+
+ parse(in);
+ }
+ }
+
+ /**
+ * Construct a DN pattern from a input stream of pattern
+ */
+ public MapRDNPattern(PushbackReader in)
+ throws ELdapException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws ELdapException {
+ //System.out.println("_________ begin rdn _________");
+ Vector avaPatterns = new Vector();
+ MapAVAPattern avaPattern = null;
+ int lastChar;
+
+ do {
+ avaPattern = new MapAVAPattern(in);
+ avaPatterns.addElement(avaPattern);
+ //System.out.println("added AVAPattern"+
+ //" mType "+avaPattern.mType+
+ //" mAttr "+avaPattern.mAttr+
+ //" mValue "+avaPattern.mValue+
+ //" mElement "+avaPattern.mElement);
+ try {
+ lastChar = in.read();
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ }
+ while (lastChar == '+');
+
+ if (lastChar != -1) {
+ try {
+ in.unread(lastChar); // pushback last ,
+ } catch (IOException e) {
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ }
+
+ mAVAPatterns = new MapAVAPattern[avaPatterns.size()];
+ avaPatterns.copyInto(mAVAPatterns);
+
+ Vector reqAttrs = new Vector();
+
+ for (int i = 0; i < mAVAPatterns.length; i++) {
+ String avaAttr = mAVAPatterns[i].getReqAttr();
+
+ if (avaAttr == null || avaAttr.length() == 0)
+ continue;
+ reqAttrs.addElement(avaAttr);
+ }
+ mReqAttrs = new String[reqAttrs.size()];
+ reqAttrs.copyInto(mReqAttrs);
+
+ Vector certAttrs = new Vector();
+
+ for (int i = 0; i < mAVAPatterns.length; i++) {
+ String avaAttr = mAVAPatterns[i].getCertAttr();
+
+ if (avaAttr == null || avaAttr.length() == 0)
+ continue;
+ certAttrs.addElement(avaAttr);
+ }
+ mCertAttrs = new String[certAttrs.size()];
+ certAttrs.copyInto(mCertAttrs);
+ }
+
+ /**
+ * Form a Ldap v3 DN string from a request and a cert subject name.
+ * @param req the request for (un)publish
+ * @param subject the subjectDN of the certificate
+ * @return Ldap v3 DN string to use for base ldap search.
+ */
+ public String formRDN(IRequest req, X500Name subject, CertificateExtensions ext)
+ throws ELdapException {
+ StringBuffer formedRDN = new StringBuffer();
+
+ for (int i = 0; i < mAVAPatterns.length; i++) {
+ if (mTestDN != null)
+ mAVAPatterns[i].mTestDN = mTestDN;
+ String ava = mAVAPatterns[i].formAVA(req, subject, ext);
+
+ if (ava != null && ava.length() > 0) {
+ if (formedRDN.length() != 0)
+ formedRDN.append("+");
+ formedRDN.append(ava);
+ }
+ }
+ //System.out.println("formed RDN "+formedRDN.toString());
+ return formedRDN.toString();
+ }
+
+ public String[] getReqAttrs() {
+ return (String[]) mReqAttrs.clone();
+ }
+
+ public String[] getCertAttrs() {
+ return (String[]) mCertAttrs.clone();
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/mappers/NoMap.java b/pki/base/common/src/com/netscape/cms/publish/mappers/NoMap.java
new file mode 100644
index 000000000..85fdaae04
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/mappers/NoMap.java
@@ -0,0 +1,108 @@
+// --- 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.cms.publish.mappers;
+
+
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.request.IRequest;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * No Map
+ *
+ * @version $Revision$, $Date$
+ */
+public class NoMap implements ILdapMapper, IExtendedPluginInfo {
+
+ public IConfigStore mConfig = null;
+
+ /**
+ * constructor if initializing from config store.
+ */
+ public NoMap() {
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String params[] = {
+ IExtendedPluginInfo.HELP_TOKEN + ";configuration-ldappublish-mapper-simplemapper",
+ IExtendedPluginInfo.HELP_TEXT + ";Describes how to form the name of the entry to publish to"
+ };
+
+ return params;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * for initializing from config store.
+ */
+ public void init(IConfigStore config)
+ throws EBaseException {
+ mConfig = config;
+ }
+
+ /**
+ * Maps a X500 subject name to LDAP entry.
+ * Uses DN pattern to form a DN for a LDAP base search.
+ *
+ * @param conn the LDAP connection.
+ * @param obj the object to map.
+ * @exception ELdapException if any LDAP exceptions occured.
+ */
+ public String map(LDAPConnection conn, Object obj)
+ throws ELdapException {
+ return null;
+ }
+
+ public String map(LDAPConnection conn, IRequest req, Object obj)
+ throws ELdapException {
+ return null;
+ }
+
+ public String getImplName() {
+ return "NoMap";
+ }
+
+ public String getDescription() {
+ return "NoMap";
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+ return v;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+ return v;
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java
new file mode 100644
index 000000000..18af1a98b
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/FileBasedPublisher.java
@@ -0,0 +1,424 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.math.*;
+import java.io.*;
+import java.security.cert.*;
+import java.util.*;
+import java.util.zip.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+import org.mozilla.jss.util.Base64OutputStream;
+
+/**
+ * This publisher writes certificate and CRL into
+ * a directory.
+ *
+ * @version $Revision$, $Date$
+ */
+public class FileBasedPublisher implements ILdapPublisher, IExtendedPluginInfo {
+ private static final String PROP_DIR = "directory";
+ private static final String PROP_DER = "Filename.der";
+ private static final String PROP_B64 = "Filename.b64";
+ private static final String PROP_LNK = "latestCrlLink";
+ private static final String PROP_GMT = "timeStamp";
+ private static final String PROP_EXT = "crlLinkExt";
+ private static final String PROP_ZIP = "zipCRLs";
+ private static final String PROP_LEV = "zipLevel";
+ private IConfigStore mConfig = null;
+ private String mDir = null;
+ private ILogger mLogger = CMS.getLogger();
+ private String mCrlIssuingPointId;
+ protected boolean mDerAttr = true;
+ protected boolean mB64Attr = false;
+ protected boolean mLatestCRL = false;
+ protected boolean mZipCRL = false;
+ protected String mTimeStamp = null;
+ protected String mLinkExt = null;
+ protected int mZipLevel = 9;
+
+ public void setIssuingPointId(String crlIssuingPointId)
+ {
+ mCrlIssuingPointId = crlIssuingPointId;
+ }
+ /**
+ * Returns the implementation name.
+ */
+ public String getImplName() {
+ return "FileBasedPublisher";
+ }
+
+ /**
+ * Returns the description of the ldap publisher.
+ */
+
+ public String getDescription() {
+ return "This publisher writes the Certificates and CRLs into files.";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ PROP_DIR + ";string;Directory in which to put the files (absolute path or relative path to cert-* instance directory).",
+ PROP_DER + ";boolean;Store certificates or CRLs into *.der files.",
+ PROP_B64 + ";boolean;Store certificates or CRLs into *.b64 files.",
+ PROP_GMT + ";choice(LocalTime,GMT);Use local time or GMT to time stamp CRL file name with CRL's 'thisUpdate' field.",
+ PROP_LNK + ";boolean;Generate link to the latest binary CRL. It requires '"+PROP_DER+"' to be enabled.",
+ PROP_EXT + ";string;Name extension used by link to the latest CRL. Default name extension is 'der'.",
+ PROP_ZIP + ";boolean;Generate compressed CRLs.",
+ PROP_LEV + ";choice(0,1,2,3,4,5,6,7,8,9);Set compression level from 0 to 9.",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-filepublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";Stores the certificates or CRLs into files. Certificate is named as cert-<serialno>.der or *.b64, and CRL is named as <IssuingPoint>-<thisUpdate-time>.der or *.b64."
+ };
+
+ return params;
+ }
+
+ /**
+ * Returns the current instance parameters.
+ */
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+ String dir = "";
+ String ext = "";
+
+ try {
+ dir = mConfig.getString(PROP_DIR);
+ } catch (EBaseException e) {
+ }
+ try {
+ ext = mConfig.getString(PROP_EXT);
+ } catch (EBaseException e) {
+ }
+ try {
+ mTimeStamp = mConfig.getString(PROP_GMT);
+ } catch (EBaseException e) {
+ }
+ try {
+ mZipLevel = mConfig.getInteger(PROP_LEV, 9);
+ } catch (EBaseException e) {
+ }
+ try {
+ if (mTimeStamp == null || (!mTimeStamp.equals("GMT")))
+ mTimeStamp = "LocalTime";
+ v.addElement(PROP_DIR+"=" + dir);
+ v.addElement(PROP_DER+"=" + mConfig.getBoolean(PROP_DER,true));
+ v.addElement(PROP_B64+"=" + mConfig.getBoolean(PROP_B64,false));
+ v.addElement(PROP_GMT+"=" + mTimeStamp);
+ v.addElement(PROP_LNK+"=" + mConfig.getBoolean(PROP_LNK,false));
+ v.addElement(PROP_EXT+"=" + ext);
+ v.addElement(PROP_ZIP+"=" + mConfig.getBoolean(PROP_ZIP,false));
+ v.addElement(PROP_LEV+"=" + mZipLevel);
+ } catch (Exception e) {
+ }
+ return v;
+ }
+
+ /**
+ * Returns the initial default parameters.
+ */
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement(PROP_DIR+"=");
+ v.addElement(PROP_DER+"=true");
+ v.addElement(PROP_B64+"=false");
+ v.addElement(PROP_GMT+"=LocalTime");
+ v.addElement(PROP_LNK+"=false");
+ v.addElement(PROP_EXT+"=");
+ v.addElement(PROP_ZIP+"=false");
+ v.addElement(PROP_LEV+"=9");
+ return v;
+ }
+
+ /**
+ * Initializes this plugin.
+ */
+ public void init(IConfigStore config) {
+ mConfig = config;
+ String dir = null;
+ String ext = null;
+
+ try {
+ dir = mConfig.getString(PROP_DIR, null);
+ mDerAttr = mConfig.getBoolean(PROP_DER, true);
+ mB64Attr = mConfig.getBoolean(PROP_B64, false);
+ mTimeStamp = mConfig.getString(PROP_GMT, "LocalTime");
+ mLatestCRL = mConfig.getBoolean(PROP_LNK, false);
+ mLinkExt = mConfig.getString(PROP_EXT, null);
+ mZipCRL = mConfig.getBoolean(PROP_ZIP, false);
+ mZipLevel = mConfig.getInteger(PROP_LEV, 9);
+ } catch (EBaseException e) {
+ }
+ if (dir == null) {
+ throw new RuntimeException("No Directory Specified");
+ }
+
+ // convert to forward slash
+ dir = dir.replace('\\', '/');
+ config.putString(PROP_DIR, dir);
+
+ File dirCheck = new File(dir);
+
+ if (dirCheck.isDirectory()) {
+ mDir = dir;
+ } else {
+ // maybe it is relative path
+ String mInstanceRoot = null;
+
+ try {
+ mInstanceRoot = CMS.getConfigStore().getString("instanceRoot");
+ } catch (Exception e) {
+ throw new RuntimeException("Invalid Instance Dir " + e);
+ }
+ dirCheck = new File(mInstanceRoot +
+ File.separator + dir);
+ if (dirCheck.isDirectory()) {
+ mDir = mInstanceRoot + File.separator + dir;
+ } else {
+ throw new RuntimeException("Invalid Directory " + dir);
+ }
+ }
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ private String[] getCrlNamePrefix(X509CRL crl, boolean useGMT) {
+ String[] namePrefix = {"crl", "crl"};
+
+ if (mCrlIssuingPointId != null && mCrlIssuingPointId.length() != 0) {
+ namePrefix[0] = mCrlIssuingPointId;
+ namePrefix[1] = mCrlIssuingPointId;
+ }
+ java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyyMMdd-HHmmss");
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ if (useGMT) format.setTimeZone(tz);
+ String timeStamp = format.format(crl.getThisUpdate()).toString();
+ namePrefix[0] += "-" + timeStamp;
+ if (((netscape.security.x509.X509CRLImpl)crl).isDeltaCRL()) {
+ namePrefix[0] += "-delta";
+ namePrefix[1] += "-delta";
+ }
+
+ return namePrefix;
+ }
+
+ private void createLink(String linkName, String fileName) {
+ String cmd = "ln -s " + fileName + " " + linkName + ".new";
+ if (com.netscape.cmsutil.util.Utils.exec(cmd)) {
+ File oldLink = new File(linkName + ".old");
+ if (oldLink.exists()) { // remove old link if exists
+ oldLink.delete();
+ }
+ File link = new File(linkName);
+ if (link.exists()) { // current link becomes an old link
+ link.renameTo(new File(linkName + ".old"));
+ }
+ File newLink = new File(linkName + ".new");
+ if (newLink.exists()) { // new link becomes current link
+ newLink.renameTo(new File(linkName));
+ }
+ oldLink = new File(linkName + ".old");
+ if (oldLink.exists()) { // remove a new old link
+ oldLink.delete();
+ }
+ } else {
+ CMS.debug("FileBasedPublisher: createLink: '" + cmd + "' --- failed");
+ }
+ }
+
+ /**
+ * Publishs a object to the ldap directory.
+ *
+ * @param conn a Ldap connection
+ * (null if LDAP publishing is not enabled)
+ * @param dn dn of the ldap entry to publish cert
+ * (null if LDAP publishing is not enabled)
+ * @param object object to publish
+ * (java.security.cert.X509Certificate or,
+ * java.security.cert.X509CRL)
+ */
+ public void publish(LDAPConnection conn, String dn, Object object)
+ throws ELdapException {
+ CMS.debug("FileBasedPublisher: publish");
+ try {
+ if (object instanceof X509Certificate) {
+ X509Certificate cert = (X509Certificate) object;
+ BigInteger sno = cert.getSerialNumber();
+ String name = mDir +
+ File.separator + "cert-" +
+ sno.toString();
+ if (mDerAttr)
+ {
+ String fileName = name + ".der";
+ FileOutputStream fos = new FileOutputStream(fileName);
+ fos.write(cert.getEncoded());
+ fos.close();
+ }
+ if (mB64Attr)
+ {
+ String fileName = name + ".b64";
+ FileOutputStream fos = new FileOutputStream(fileName);
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ Base64OutputStream b64 =
+ new Base64OutputStream(new PrintStream(new FilterOutputStream(output)));
+ b64.write(cert.getEncoded());
+ b64.flush();
+ (new PrintStream(fos)).print(output.toString("8859_1"));
+ fos.close();
+ }
+ } else if (object instanceof X509CRL) {
+ X509CRL crl = (X509CRL) object;
+ String[] namePrefix = getCrlNamePrefix(crl, mTimeStamp.equals("GMT"));
+ String baseName = mDir + File.separator + namePrefix[0];
+ String tempFile = baseName + ".temp";
+ FileOutputStream fos;
+ ZipOutputStream zos;
+ byte [] encodedArray = null;
+ File destFile = null;
+ String destName = null;
+ File renameFile = null;
+
+ if (mDerAttr) {
+ fos = new FileOutputStream(tempFile);
+ encodedArray = crl.getEncoded();
+ fos.write(encodedArray);
+ fos.close();
+ if (mZipCRL) {
+ zos = new ZipOutputStream(new FileOutputStream(baseName+".zip"));
+ zos.setLevel(mZipLevel);
+ zos.putNextEntry(new ZipEntry(baseName+".der"));
+ zos.write(encodedArray, 0, encodedArray.length);
+ zos.closeEntry();
+ zos.close();
+ }
+ destName = baseName + ".der";
+ destFile = new File(destName);
+
+ if (destFile.exists())
+ destFile.delete();
+ renameFile = new File(tempFile);
+ renameFile.renameTo(destFile);
+
+ if (mLatestCRL) {
+ String linkExt = ".";
+ if (mLinkExt != null && mLinkExt.length() > 0) {
+ linkExt += mLinkExt;
+ } else {
+ linkExt += "der";
+ }
+ String linkName = mDir + File.separator + namePrefix[1] + linkExt;
+ createLink(linkName, destName);
+ if (mZipCRL) {
+ linkName = mDir + File.separator + namePrefix[1] + ".zip";
+ createLink(linkName, baseName+".zip");
+ }
+ }
+ }
+
+ // output base64 file
+ if(mB64Attr==true)
+ {
+ if (encodedArray ==null)
+ encodedArray = crl.getEncoded();
+
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ fos = new FileOutputStream(tempFile);
+ fos.write(com.netscape.osutil.OSUtil.BtoA(encodedArray).getBytes());
+ fos.close();
+ destName = baseName + ".b64";
+ destFile = new File(destName);
+
+ if(destFile.exists())
+ destFile.delete();
+ renameFile = new File(tempFile);
+ renameFile.renameTo(destFile);
+ }
+ }
+ } catch (IOException e) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString()));
+ } catch (CertificateEncodingException e) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString()));
+ } catch (CRLException e) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_FILE_PUBLISHER_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * Unpublishs a object to the ldap directory.
+ *
+ * @param conn the Ldap connection
+ * (null if LDAP publishing is not enabled)
+ * @param dn dn of the ldap entry to unpublish cert
+ * (null if LDAP publishing is not enabled)
+ * @param object object to unpublish
+ * (java.security.cert.X509Certificate)
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object object)
+ throws ELdapException {
+ CMS.debug("FileBasedPublisher: unpublish");
+ String name = mDir + File.separator;
+ String fileName;
+
+ if (object instanceof X509Certificate) {
+ X509Certificate cert = (X509Certificate) object;
+ BigInteger sno = cert.getSerialNumber();
+ name += "cert-" + sno.toString();
+ } else if (object instanceof X509CRL) {
+ X509CRL crl = (X509CRL) object;
+ String[] namePrefix = getCrlNamePrefix(crl, mTimeStamp.equals("GMT"));
+ name += namePrefix[0];
+
+ fileName = name + ".zip";
+ File f = new File(fileName);
+ f.delete();
+ }
+ fileName = name + ".der";
+ File f = new File(fileName);
+ f.delete();
+
+ fileName = name + ".b64";
+ f = new File(fileName);
+ f.delete();
+ }
+ /**
+ * returns the Der attribute where it'll be published.
+ */
+ public boolean getDerAttr() {
+ return mDerAttr;
+ }
+ /**
+ * returns the B64 attribute where it'll be published.
+ */
+ public boolean getB64Attr() {
+ return mB64Attr;
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java
new file mode 100644
index 000000000..5b6533e13
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCaCertPublisher.java
@@ -0,0 +1,408 @@
+// --- 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.cms.publish.publishers;
+
+
+import netscape.ldap.*;
+import java.security.cert.*;
+import java.io.*;
+import java.util.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Interface for publishing a CA certificate to
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCaCertPublisher
+ implements ILdapPublisher, IExtendedPluginInfo {
+ public static final String LDAP_CACERT_ATTR = "caCertificate;binary";
+ public static final String LDAP_CA_OBJECTCLASS = "pkiCA";
+ public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary";
+ public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary";
+
+ protected String mCaCertAttr = LDAP_CACERT_ATTR;
+ protected String mCaObjectclass = LDAP_CA_OBJECTCLASS;
+ protected String mObjAdded = "";
+ protected String mObjDeleted = "";
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+ private String mcrlIssuingPointId;
+
+
+ /**
+ * constructor constructs default values.
+ */
+ public LdapCaCertPublisher() {
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String s[] = {
+ "caCertAttr;string;Name of Ldap attribute in which to store certificate",
+ "caObjectClass;string;The name of the objectclasses which should be " +
+ "added to this entry, if they do not already exist. This can be " +
+ "'certificationAuthority' (if using RFC 2256) or 'pkiCA' (if using RFC 4523)",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-cacertpublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin knows how to publish the CA cert to " +
+ "'certificateAuthority' and 'pkiCA' -type entries"
+ };
+
+ return s;
+ }
+
+ public String getImplName() {
+ return "LdapCaCertPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapCaCertPublisher";
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("caCertAttr=" + mCaCertAttr);
+ v.addElement("caObjectClass=" + mCaObjectclass);
+ return v;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("caCertAttr=" + mCaCertAttr);
+ v.addElement("caObjectClass=" + mCaObjectclass);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR);
+ mCaObjectclass = mConfig.getString("caObjectClass",
+ LDAP_CA_OBJECTCLASS);
+ mObjAdded = mConfig.getString("caObjectClassAdded", "");
+ mObjDeleted = mConfig.getString("caObjectClassDeleted", "");
+ mInited = true;
+ }
+
+ // don't think anyone would ever use this but just in case.
+ public LdapCaCertPublisher(String caCertAttr, String caObjectclass) {
+ mCaCertAttr = caCertAttr;
+ mCaObjectclass = caObjectclass;
+ mInited = true;
+ }
+
+ /**
+ * Gets the CA object class to convert to.
+ */
+ public String getCAObjectclass() {
+ return mCaObjectclass;
+ }
+
+ /**
+ * returns the ca cert attribute where it'll be published.
+ */
+ public String getCaCertAttrName() {
+ return mCaCertAttr;
+ }
+
+ /**
+ * publish a CA certificate
+ * Adds the cert to the multi-valued certificate attribute as a
+ * DER encoded binary blob. Does not check if cert already exists.
+ * Converts the class to certificateAuthority.
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the certificate
+ * @param certObj the certificate object.
+ */
+ public void publish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (conn == null) {
+ log(ILogger.LL_INFO, "LdapCaCertPublisher: no LDAP connection");
+ return;
+ }
+
+ try {
+ mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR);
+ mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS);
+ } catch (EBaseException e) {
+ }
+
+ // Bugscape #56124 - support multiple publishing directory
+ // see if we should create local connection
+ LDAPConnection altConn = null;
+ try {
+ String host = mConfig.getString("host", null);
+ String port = mConfig.getString("port", null);
+ if (host != null && port != null) {
+ int portVal = Integer.parseInt(port);
+ int version = Integer.parseInt(mConfig.getString("version", "2"));
+ String cert_nick = mConfig.getString("clientCertNickname", null);
+ LDAPSSLSocketFactoryExt sslSocket = null;
+ if (cert_nick != null) {
+ sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+ }
+ String mgr_dn = mConfig.getString("bindDN", null);
+ String mgr_pwd = mConfig.getString("bindPWD", null);
+
+ altConn = CMS.getBoundConnection(host, portVal,
+ version,
+ sslSocket, mgr_dn, mgr_pwd);
+ conn = altConn;
+ }
+ } catch (LDAPException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ } catch (EBaseException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ }
+
+
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ /* search for attribute names to determine existence of attributes */
+ LDAPSearchResults res =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { LDAP_CRL_ATTR, LDAP_ARL_ATTR }, true);
+ LDAPEntry entry = res.next();
+ LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR);
+ LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR);
+
+ /* search for objectclass and caCert values */
+ LDAPSearchResults res1 =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { "objectclass", mCaCertAttr }, false);
+ LDAPEntry entry1 = res1.next();
+ LDAPAttribute ocs = entry1.getAttribute("objectclass");
+ LDAPAttribute certs = entry1.getAttribute(mCaCertAttr);
+
+ boolean hasCert =
+ LdapUserCertPublisher.ByteValueExists(certs, certEnc);
+
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ if (hasCert) {
+ log(ILogger.LL_INFO, "publish: CA " + dn + " already has Cert");
+ } else {
+ /*
+ fix for 360458 - if no cert, use add, if has cert but
+ not equal, use replace
+ */
+ if (certs == null) {
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(mCaCertAttr, certEnc));
+ log(ILogger.LL_INFO, "CA cert added");
+ } else {
+ modSet.add(LDAPModification.REPLACE,
+ new LDAPAttribute(mCaCertAttr, certEnc));
+ log(ILogger.LL_INFO, "CA cert replaced");
+ }
+ }
+
+ String[] oclist = mCaObjectclass.split(",");
+
+ boolean attrsAdded = false;
+ for (int i=0; i < oclist.length; i++) {
+ String oc = oclist[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc);
+ if (!hasoc) {
+ log(ILogger.LL_INFO, "adding CA objectclass " + oc + " to " + dn);
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute("objectclass", oc));
+
+ if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) {
+ // add MUST attributes
+ if (arls == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_ARL_ATTR, ""));
+ if (crls == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_CRL_ATTR, ""));
+ attrsAdded = true;
+ }
+ }
+ }
+
+ // delete objectclasses that have been deleted from config
+ String[] delList = mObjDeleted.split(",");
+ if (delList.length > 0) {
+ for (int i=0; i< delList.length; i++) {
+ String deloc = delList[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc);
+ boolean match = false;
+ for (int j=0; j< oclist.length; j++) {
+ if ((oclist[j].trim()).equals(deloc)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match && hasoc) {
+ log(ILogger.LL_INFO, "deleting CA objectclass " + deloc + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute("objectclass", deloc));
+ }
+ }
+ }
+
+ // reset mObjAdded and mObjDeleted, if needed
+ if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) {
+ mObjAdded = "";
+ mObjDeleted = "";
+ mConfig.putString("caObjectClassAdded", "");
+ mConfig.putString("caObjectClassDeleted", "");
+ try {
+ mConfig.commit(false);
+ } catch (Exception e) {
+ log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted");
+ }
+ }
+
+ if (modSet.size() > 0) conn.modify(dn, modSet);
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CANT_DECODE_CERT", dn));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CACERT_ERROR", e.toString()));
+ }
+ } finally {
+ if (altConn != null) {
+ try {
+ altConn.disconnect();
+ } catch (LDAPException e) {
+ // safely ignored
+ }
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * deletes the certificate from CA's certificate attribute.
+ * if it's the last cert will also remove the certificateAuthority
+ * objectclass.
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ try {
+ mCaCertAttr = mConfig.getString("caCertAttr", LDAP_CACERT_ATTR);
+ mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS);
+ } catch (EBaseException e) {
+ }
+
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ LDAPSearchResults res =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { mCaCertAttr, "objectclass" }, false);
+
+ LDAPEntry entry = res.next();
+ LDAPAttribute certs = entry.getAttribute(mCaCertAttr);
+ LDAPAttribute ocs = entry.getAttribute("objectclass");
+
+ boolean hasCert =
+ LdapUserCertPublisher.ByteValueExists(certs, certEnc);
+
+ if (!hasCert) {
+ log(ILogger.LL_INFO, "unpublish: " + dn + " has not cert already");
+ //throw new ELdapException(
+ // LdapResources.ALREADY_UNPUBLISHED_1, dn);
+ return;
+ }
+
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute(mCaCertAttr, certEnc));
+ if (certs.size() == 1) {
+ // if last ca cert, remove oc also.
+
+ String[] oclist = mCaObjectclass.split(",");
+ for (int i =0 ; i < oclist.length; i++) {
+ String oc = oclist[i].trim();
+ boolean hasOC = LdapUserCertPublisher.StringValueExists(ocs, oc);
+ if (hasOC) {
+ log(ILogger.LL_INFO, "unpublish: deleting CA oc" + oc + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute("objectclass", oc));
+ }
+ }
+ }
+ conn.modify(dn, modSet);
+ } catch (CertificateEncodingException e) {
+ CMS.debug("LdapCaCertPublisher: unpublish: Cannot decode cert for " + dn);
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_CACERT_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ /**
+ * handy routine for logging in this class.
+ */
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCaPublisher: " + msg);
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java
new file mode 100644
index 000000000..654a93150
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertSubjPublisher.java
@@ -0,0 +1,332 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.io.*;
+import java.util.*;
+import netscape.ldap.*;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Interface for mapping a X509 certificate to a LDAP entry
+ * Publishes a certificate as binary and its subject name.
+ * there is one subject name value for each certificate.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCertSubjPublisher implements ILdapPublisher {
+ public static final String LDAP_CERTSUBJNAME_ATTR = "certSubjectName";
+ protected String mCertAttr = LdapUserCertPublisher.LDAP_USERCERT_ATTR;
+ protected String mSubjNameAttr = LDAP_CERTSUBJNAME_ATTR;
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+
+ /**
+ * constructor using default certificate subject name and attribute for
+ * publishing subject name.
+ */
+ public LdapCertSubjPublisher() {
+ }
+
+ public String getImplName() {
+ return "LdapCertSubjPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapCertSubjPublisher";
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ v.addElement("subjectNameAttr=" + mSubjNameAttr);
+ return v;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ v.addElement("subjectNameAttr=" + mSubjNameAttr);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCertAttr = mConfig.getString("certAttr",
+ LdapUserCertPublisher.LDAP_USERCERT_ATTR);
+ mSubjNameAttr = mConfig.getString("certSubjectName",
+ LDAP_CERTSUBJNAME_ATTR);
+ mInited = true;
+ }
+
+ /**
+ * constrcutor using specified certificate attribute and
+ * certificate subject name attribute.
+ */
+ public LdapCertSubjPublisher(String certAttr, String subjNameAttr) {
+ mCertAttr = certAttr;
+ mSubjNameAttr = subjNameAttr;
+ }
+
+ public String getCertAttr() {
+ return mCertAttr;
+ }
+
+ public String getSubjNameAttr() {
+ return mSubjNameAttr;
+ }
+
+ public void setSubjNameAttr(String subjNameAttr) {
+ mSubjNameAttr = subjNameAttr;
+ }
+
+ public void setCertAttr(String certAttr) {
+ mCertAttr = certAttr;
+ }
+
+ /**
+ * publish a user certificate
+ * Adds the cert to the multi-valued certificate attribute as a
+ * DER encoded binary blob. Does not check if cert already exists.
+ * Then adds the subject name of the cert to the subject name attribute.
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the certificate
+ * @param certObj the certificate object.
+ * @exception ELdapException if cert or subject name already exists,
+ * if cert encoding fails, if getting cert subject name fails.
+ * Use ELdapException.getException() to find underlying exception.
+ */
+ public void publish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (conn == null) {
+ log(ILogger.LL_INFO, "LdapCertSubjPublisher: no LDAP connection");
+ return;
+ }
+
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ try {
+ boolean hasCert = false, hasSubjname = false;
+ byte[] certEnc = cert.getEncoded();
+ String subjName = ((X500Name) cert.getSubjectDN()).toLdapDNString();
+
+ LDAPSearchResults res =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { mCertAttr, mSubjNameAttr }, false);
+
+ LDAPEntry entry = res.next();
+ LDAPAttribute certs = entry.getAttribute(mCertAttr);
+ LDAPAttribute subjnames = entry.getAttribute(mSubjNameAttr);
+
+ // check if has cert already.
+ if (certs != null) {
+ hasCert = LdapUserCertPublisher.ByteValueExists(certs, certEnc);
+ }
+
+ // check if has subject name already.
+ if (subjnames != null) {
+ hasSubjname =
+ LdapUserCertPublisher.StringValueExists(subjnames, subjName);
+ }
+
+ // if has both, done.
+ if (hasCert && hasSubjname) {
+ log(ILogger.LL_INFO,
+ "publish: " + subjName + " already has cert & subject name");
+ return;
+ }
+
+ // add cert if not already there.
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ if (!hasCert) {
+ log(ILogger.LL_INFO, "publish: adding cert to " + subjName);
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(mCertAttr, certEnc));
+ }
+ // add subject name if not already there.
+ if (!hasSubjname) {
+ log(ILogger.LL_INFO, "publish: adding " + subjName + " to " + dn);
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(mSubjNameAttr, subjName));
+ }
+ conn.modify(dn, modSet);
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * deletes the certificate from the list of certificates.
+ * does not check if certificate is already there.
+ * also takes out the subject name if no other certificate remain
+ * with the same subject name.
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ try {
+ boolean hasCert = false, hasSubjname = false;
+ boolean hasAnotherCert = false;
+ X509Certificate cert = (X509Certificate) certObj;
+ String subjName = ((X500Name) cert.getSubjectDN()).toLdapDNString();
+
+ byte[] certEnc = cert.getEncoded();
+
+ LDAPSearchResults res =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { mCertAttr, mSubjNameAttr }, false);
+
+ LDAPEntry entry = res.next();
+ LDAPAttribute certs = entry.getAttribute(mCertAttr);
+ LDAPAttribute subjnames = entry.getAttribute(mSubjNameAttr);
+
+ // check for cert and other certs with same subject name.
+ if (certs != null) {
+ hasCert = LdapUserCertPublisher.ByteValueExists(certs, certEnc);
+ // check for other certs with the same subject name
+ Enumeration vals = certs.getByteValues();
+ byte[] val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (byte[]) vals.nextElement();
+ if (Utils.byteArraysAreEqual(certEnc, val)) {
+ hasCert = true;
+ continue;
+ }
+ try {
+ X509CertImpl certval = new X509CertImpl(val);
+ // XXX use some sort of X500name equals function here.
+ String subjnam =
+ ((X500Name) certval.getSubjectDN()).toLdapDNString();
+
+ if (subjnam.equalsIgnoreCase(subjName)) {
+ hasAnotherCert = true;
+ }
+ } catch (CertificateEncodingException e) {
+ // ignore this certificate.
+ CMS.debug(
+ "LdapCertSubjPublisher: unpublish: an invalid cert in dn entry encountered");
+ } catch (CertificateException e) {
+ // ignore this certificate.
+ CMS.debug(
+ "LdapCertSubjPublisher: unpublish: an invalid cert in dn entry encountered");
+ }
+ }
+ }
+
+ // check if doesn't have subject name already.
+ if (subjnames != null) {
+ hasSubjname =
+ LdapUserCertPublisher.StringValueExists(subjnames, subjName);
+ }
+
+ // if doesn't have both, done.
+ if (!hasCert && !hasSubjname) {
+ log(ILogger.LL_INFO,
+ "unpublish: " + subjName + " already has not cert & subjname");
+ return;
+ }
+
+ // delete cert if there.
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ if (hasCert) {
+ log(ILogger.LL_INFO,
+ "unpublish: deleting cert " + subjName + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute(mCertAttr, certEnc));
+ }
+ // delete subject name if no other cert has the same name.
+ if (hasSubjname && !hasAnotherCert) {
+ log(ILogger.LL_INFO,
+ "unpublish: deleting subject name " + subjName + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute(mSubjNameAttr, subjName));
+ }
+ conn.modify(dn, modSet);
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (CertificateException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_DECODING_CERT_FAILED", e.toString()));
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_LDAP_DN_STRING_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCertSubjPublisher: " + msg);
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java
new file mode 100644
index 000000000..ca8a07ef4
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCertificatePairPublisher.java
@@ -0,0 +1,306 @@
+// --- 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.cms.publish.publishers;
+
+
+import netscape.ldap.*;
+import java.security.cert.*;
+import java.io.*;
+import java.util.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * module for publishing a cross certificate pair to ldap
+ * crossCertificatePair attribute
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCertificatePairPublisher
+ implements ILdapPublisher, IExtendedPluginInfo {
+ public static final String LDAP_CROSS_CERT_PAIR_ATTR = "crossCertificatePair;binary";
+ public static final String LDAP_CA_OBJECTCLASS = "pkiCA";
+ public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary";
+ public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary";
+ public static final String LDAP_CACERT_ATTR = "caCertificate;binary";
+
+ protected String mCrossCertPairAttr = LDAP_CROSS_CERT_PAIR_ATTR;
+ protected String mCaObjectclass = LDAP_CA_OBJECTCLASS;
+ protected String mObjAdded = "";
+ protected String mObjDeleted = "";
+
+ private ILogger mLogger = CMS.getLogger();
+ private boolean mInited = false;
+ protected IConfigStore mConfig = null;
+
+ /**
+ * constructor constructs default values.
+ */
+ public LdapCertificatePairPublisher() {
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String s[] = {
+ "crossCertPairAttr;string;Name of Ldap attribute in which to store cross certificates",
+ "caObjectClass;string;The name of the objectclasses which should be " +
+ "added to this entry, if they do not already exist. This can be " +
+ "'certificationAuthority' (if using RFC 2256) or 'pkiCA' (if using RFC 4523)",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-crosscertpairpublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin knows how to publish the CA cert to " +
+ "'certificateAuthority' and 'pkiCA' -type entries"
+ };
+
+ return s;
+ }
+
+ public String getImplName() {
+ return "LdapCertificatePairPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapCertificatePairPublisher";
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("crossCertPairAttr=" + mCrossCertPairAttr);
+ v.addElement("caObjectClass=" + mCaObjectclass);
+ return v;
+ }
+
+ public Vector getInstanceParamsWithExtras() {
+ return getInstanceParams();
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("crossCertPairAttr=" + mCrossCertPairAttr);
+ v.addElement("caObjectClass=" + mCaObjectclass);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCrossCertPairAttr = mConfig.getString("crossCertPairAttr", LDAP_CROSS_CERT_PAIR_ATTR);
+ mCaObjectclass = mConfig.getString("caObjectClass",
+ LDAP_CA_OBJECTCLASS);
+ mObjAdded = mConfig.getString("caObjectClassAdded", "");
+ mObjDeleted = mConfig.getString("caObjectClassDeleted", "");
+
+ mInited = true;
+ }
+
+ // don't think anyone would ever use this but just in case.
+ public LdapCertificatePairPublisher(String crossCertPairAttr, String caObjectclass) {
+ mCrossCertPairAttr = crossCertPairAttr;
+ mCaObjectclass = caObjectclass;
+ mInited = true;
+ }
+
+ /**
+ * Gets the Certificate Authority object class to convert to.
+ */
+ public String getCAObjectclass() {
+ return mCaObjectclass;
+ }
+
+ /**
+ * returns the cross cert pair attribute where it'll be published.
+ */
+ public String getXCertAttrName() {
+ return mCrossCertPairAttr;
+ }
+
+ /**
+ * publish a certificatePair
+ * -should not be called from listeners.
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the XcertificatePair
+ * @param pair the Xcertificate bytes object.
+ */
+ public synchronized void publish(LDAPConnection conn, String dn, Object pair)
+ throws ELdapException {
+ publish(conn, dn, (byte[]) pair);
+ }
+
+ /**
+ * publish a certificatePair
+ * -should not be called from listeners.
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the XcertificatePair
+ * @param pair the cross cert bytes
+ */
+ public synchronized void publish(LDAPConnection conn, String dn,
+ byte[] pair)
+ throws ELdapException {
+
+ if (conn == null) {
+ log(ILogger.LL_INFO, "LdapCertificatePairPublisher: no LDAP connection");
+ return;
+ }
+
+ try {
+ mCrossCertPairAttr = mConfig.getString("crossCertPairAttr", LDAP_CROSS_CERT_PAIR_ATTR);
+ mCaObjectclass = mConfig.getString("caObjectClass", LDAP_CA_OBJECTCLASS);
+ } catch (EBaseException e) {
+ }
+
+ try {
+ // search for attributes to determine if they exist
+ LDAPSearchResults res =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { LDAP_CACERT_ATTR, LDAP_CRL_ATTR, LDAP_ARL_ATTR }, true);
+ LDAPEntry entry = res.next();
+ LDAPAttribute certs = entry.getAttribute(LDAP_CACERT_ATTR);
+ LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR);
+ LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR);
+
+ // search for objectclass and crosscertpair attributes and values
+ LDAPSearchResults res1 =
+ conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { "objectclass", mCrossCertPairAttr }, false);
+ LDAPEntry entry1 = res1.next();
+ LDAPAttribute ocs = entry1.getAttribute("objectclass");
+ LDAPAttribute certPairs = entry1.getAttribute("crosscertificatepair;binary");
+
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ boolean hasCert = LdapUserCertPublisher.ByteValueExists(certPairs, pair);
+ if (LdapUserCertPublisher.ByteValueExists(certPairs, pair)) {
+ CMS.debug("LdapCertificatePairPublisher: cross cert pair bytes exist in publishing directory, do not publish again.");
+ return;
+ }
+ if (hasCert) {
+ log(ILogger.LL_INFO, "publish: CA " + dn + " already has cross cert pair bytes");
+ } else {
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(mCrossCertPairAttr, pair));
+ log(ILogger.LL_INFO, "cross cert pair published with dn=" + dn);
+ }
+
+ String[] oclist = mCaObjectclass.split(",");
+
+ boolean attrsAdded = false;
+ for (int i=0; i < oclist.length; i++) {
+ String oc = oclist[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc);
+ if (!hasoc) {
+ log(ILogger.LL_INFO, "adding CA objectclass " + oc + " to " + dn);
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute("objectclass", oc));
+
+ if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) {
+ // add MUST attributes
+ if (arls == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_ARL_ATTR, ""));
+ if (crls == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_CRL_ATTR, ""));
+ if (certs == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_CACERT_ATTR, ""));
+ attrsAdded = true;
+ }
+ }
+ }
+
+ // delete objectclasses that have been deleted from config
+ String[] delList = mObjDeleted.split(",");
+ if (delList.length > 0) {
+ for (int i=0; i< delList.length; i++) {
+ String deloc = delList[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc);
+ boolean match = false;
+ for (int j=0; j< oclist.length; j++) {
+ if ((oclist[j].trim()).equals(deloc)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match && hasoc) {
+ log(ILogger.LL_INFO, "deleting CRL objectclass " + deloc + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute("objectclass", deloc));
+ }
+ }
+ }
+
+ // reset mObjAdded and mObjDeleted, if needed
+ if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) {
+ mObjAdded = "";
+ mObjDeleted = "";
+ mConfig.putString("caObjectClassAdded", "");
+ mConfig.putString("caObjectClassDeleted", "");
+ try {
+ mConfig.commit(false);
+ } catch (Exception e) {
+ log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted");
+ }
+ }
+
+ if (modSet.size() > 0) conn.modify(dn, modSet);
+ CMS.debug("LdapCertificatePairPublisher: in publish() just published");
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISHER_EXCEPTION", "", e.toString()));
+ throw new ELdapException("error publishing cross cert pair:" + e.toString());
+ }
+ }
+ return;
+ }
+
+ /**
+ * unsupported
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ CMS.debug("LdapCertificatePairPublisher: unpublish() is unsupported in this revision");
+ }
+
+ /**
+ * handy routine for logging in this class.
+ */
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCertificatePairPublisher: " + msg);
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java
new file mode 100644
index 000000000..074d21ee0
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapCrlPublisher.java
@@ -0,0 +1,367 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.io.*;
+import java.util.*;
+import java.security.cert.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * For publishing master or global CRL.
+ * Publishes (replaces) the CRL in the CA's LDAP entry.
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapCrlPublisher implements ILdapPublisher, IExtendedPluginInfo {
+ private ILogger mLogger = CMS.getLogger();
+ protected IConfigStore mConfig = null;
+ boolean mInited = false;
+
+ public static final String LDAP_CACERT_ATTR = "caCertificate;binary";
+ public static final String LDAP_ARL_ATTR = "authorityRevocationList;binary";
+ public static final String LDAP_CRL_ATTR = "certificateRevocationList;binary";
+ public static final String LDAP_CRL_OBJECTCLASS = "pkiCA,deltaCRL";
+
+ protected String mCrlAttr = LDAP_CRL_ATTR;
+ protected String mCrlObjectClass = LDAP_CRL_OBJECTCLASS;
+ protected String mObjAdded = "";
+ protected String mObjDeleted = "";
+
+ /**
+ * constructs ldap crl publisher with default values
+ */
+ public LdapCrlPublisher() {
+ }
+
+ public String getImplName() {
+ return "LdapCrlPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapCrlPublisher";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ "crlAttr;string;Name of Ldap attribute in which to store the CRL",
+ "crlObjectClass;string;The name of the objectclasses which should be " +
+ "added to this entry, if they do not already exist. This can be a comma-" +
+ "separated list such as 'certificationAuthority,certificationAuthority-V2' " +
+ "(if using RFC 2256) or 'pkiCA, deltaCRL' (if using RFC 4523)",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-crlpublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin knows how to publish CRL's to " +
+ "'certificateAuthority' and 'pkiCA' -type entries"
+ };
+
+ return params;
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("crlAttr=" + mCrlAttr);
+ v.addElement("crlObjectClass=" + mCrlObjectClass);
+ return v;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("crlAttr=" + mCrlAttr);
+ v.addElement("crlObjectClass=" + mCrlObjectClass);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR);
+ mCrlObjectClass = mConfig.getString("crlObjectClass",
+ LDAP_CRL_OBJECTCLASS);
+ mObjAdded = mConfig.getString("crlObjectClassAdded", "");
+ mObjDeleted = mConfig.getString("crlObjectClassDeleted", "");
+
+ mInited = true;
+ }
+
+ public LdapCrlPublisher(String crlAttr, String crlObjectClass) {
+ mCrlAttr = crlAttr;
+ mCrlObjectClass = crlObjectClass;
+ }
+
+ /**
+ * Gets the CA object class to convert to.
+ */
+ public String getCRLObjectclass() {
+ return mCrlObjectClass;
+ }
+
+ /**
+ * Replaces the CRL in the certificateRevocationList attribute.
+ * CRL's are published as a DER encoded blob.
+ */
+ public void publish(LDAPConnection conn, String dn, Object crlObj)
+ throws ELdapException {
+ if (conn == null) {
+ log(ILogger.LL_INFO, "publish CRL: no LDAP connection");
+ return;
+ }
+
+ try {
+ mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR);
+ mCrlObjectClass = mConfig.getString("crlObjectClass", LDAP_CRL_OBJECTCLASS);
+ } catch (EBaseException e) {
+ }
+
+ // Bugscape #56124 - support multiple publishing directory
+ // see if we should create local connection
+ LDAPConnection altConn = null;
+ try {
+ String host = mConfig.getString("host", null);
+ String port = mConfig.getString("port", null);
+ if (host != null && port != null) {
+ int portVal = Integer.parseInt(port);
+ int version = Integer.parseInt(mConfig.getString("version", "2"));
+ String cert_nick = mConfig.getString("clientCertNickname", null);
+ LDAPSSLSocketFactoryExt sslSocket = null;
+ if (cert_nick != null) {
+ sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+ }
+ String mgr_dn = mConfig.getString("bindDN", null);
+ String mgr_pwd = mConfig.getString("bindPWD", null);
+
+ altConn = CMS.getBoundConnection(host, portVal,
+ version,
+ sslSocket, mgr_dn, mgr_pwd);
+ conn = altConn;
+ }
+ } catch (LDAPException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ } catch (EBaseException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ }
+
+ try {
+ byte[] crlEnc = ((X509CRL) crlObj).getEncoded();
+ log(ILogger.LL_INFO, "publish CRL: " + dn);
+
+ /* search for attribute names to determine existence of attributes */
+ LDAPSearchResults res = null;
+ if (mCrlAttr.equals(LDAP_CRL_ATTR)) {
+ res = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { LDAP_CACERT_ATTR, LDAP_ARL_ATTR }, true);
+ } else {
+ res = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { LDAP_CRL_ATTR, LDAP_CACERT_ATTR, LDAP_ARL_ATTR }, true);
+ }
+
+ LDAPEntry entry = res.next();
+ LDAPAttribute crls = entry.getAttribute(LDAP_CRL_ATTR);
+ LDAPAttribute certs = entry.getAttribute(LDAP_CACERT_ATTR);
+ LDAPAttribute arls = entry.getAttribute(LDAP_ARL_ATTR);
+
+ /* get object class values */
+ LDAPSearchResults res1 = null;
+ res1 = conn.search(dn, LDAPv2.SCOPE_BASE, "(objectclass=*)",
+ new String[] { "objectclass" }, false);
+ LDAPEntry entry1 = res1.next();
+ LDAPAttribute ocs = entry1.getAttribute("objectclass");
+
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ String[] oclist = mCrlObjectClass.split(",");
+ boolean attrsAdded = false;
+ for (int i=0; i < oclist.length; i++) {
+ String oc = oclist[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, oc);
+ if (!hasoc) {
+ log(ILogger.LL_INFO, "adding CRL objectclass " + oc + " to " + dn);
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute("objectclass", oc));
+
+ if ((!attrsAdded) && oc.equalsIgnoreCase("certificationAuthority")) {
+ // add MUST attributes
+ if (arls == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_ARL_ATTR, ""));
+ if (certs == null)
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_CACERT_ATTR, ""));
+
+ if ((crls == null) && (!mCrlAttr.equals(LDAP_CRL_ATTR)))
+ modSet.add(LDAPModification.ADD,
+ new LDAPAttribute(LDAP_CRL_ATTR, ""));
+ attrsAdded = true;
+ }
+ }
+ }
+
+ modSet.add(LDAPModification.REPLACE, new LDAPAttribute(mCrlAttr, crlEnc));
+
+ // delete objectclasses that have been deleted from config
+ String[] delList = mObjDeleted.split(",");
+ if (delList.length > 0) {
+ for (int i=0; i< delList.length; i++) {
+ String deloc = delList[i].trim();
+ boolean hasoc = LdapUserCertPublisher.StringValueExists(ocs, deloc);
+ boolean match = false;
+ for (int j=0; j< oclist.length; j++) {
+ if ((oclist[j].trim()).equals(deloc)) {
+ match = true;
+ break;
+ }
+ }
+ if (!match && hasoc) {
+ log(ILogger.LL_INFO, "deleting CRL objectclass " + deloc + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute("objectclass", deloc));
+ }
+ }
+ }
+
+ // reset mObjAdded and mObjDeleted, if needed
+ if ((!mObjAdded.equals("")) || (!mObjDeleted.equals(""))) {
+ mObjAdded = "";
+ mObjDeleted = "";
+ mConfig.putString("crlObjectClassAdded", "");
+ mConfig.putString("crlObjectClassDeleted", "");
+ try {
+ mConfig.commit(false);
+ } catch (Exception e) {
+ log(ILogger.LL_INFO, "Failure in updating mObjAdded and mObjDeleted");
+ }
+ }
+
+ conn.modify(dn, modSet);
+ } catch (CRLException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString()));
+ }
+ } finally {
+ if (altConn != null) {
+ try {
+ altConn.disconnect();
+ } catch (LDAPException e) {
+ // safely ignored
+ }
+ }
+ }
+
+ }
+
+ /**
+ * There shouldn't be a need to call this.
+ * CRLs are always replaced but this is implemented anyway in case
+ * there is ever a reason to remove a global CRL.
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object crlObj)
+ throws ELdapException {
+ try {
+ byte[] crlEnc = ((X509CRL) crlObj).getEncoded();
+
+ try {
+ mCrlAttr = mConfig.getString("crlAttr", LDAP_CRL_ATTR);
+ mCrlObjectClass = mConfig.getString("crlObjectClass", LDAP_CRL_OBJECTCLASS);
+ } catch (EBaseException e) {
+ }
+
+
+ LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mCrlAttr, "objectclass" }, false);
+ LDAPEntry e = res.next();
+ LDAPAttribute crls = e.getAttribute(mCrlAttr);
+ LDAPAttribute ocs = e.getAttribute("objectclass");
+
+ LDAPModificationSet modSet = new LDAPModificationSet();
+
+ boolean hasOC = false;
+ boolean hasCRL =
+ LdapUserCertPublisher.ByteValueExists(crls, crlEnc);
+
+ if (hasCRL) {
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute(mCrlAttr, crlEnc));
+ }
+
+ String[] oclist = mCrlObjectClass.split(",");
+ for (int i=0; i < oclist.length; i++) {
+ String oc = oclist[i].trim();
+ if (LdapUserCertPublisher.StringValueExists(ocs, oc)) {
+ log(ILogger.LL_INFO, "unpublish: deleting CRL object class " + oc + " from " + dn);
+ modSet.add(LDAPModification.DELETE,
+ new LDAPAttribute("objectClass", oc));
+ hasOC = true;
+ }
+ }
+
+ if (hasCRL || hasOC) {
+ conn.modify(dn, modSet);
+ } else {
+ log(ILogger.LL_INFO,
+ "unpublish: " + dn + " already has not CRL");
+ }
+ } catch (CRLException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_CRL_ERROR", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_CRL_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapCrlPublisher: " + msg);
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java
new file mode 100644
index 000000000..543088ecb
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapEncryptCertPublisher.java
@@ -0,0 +1,342 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.io.*;
+import java.math.*;
+import netscape.ldap.*;
+import java.security.cert.*;
+import java.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.publish.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.ca.*;
+import com.netscape.certsrv.apps.*;
+import netscape.security.x509.*;
+
+
+/**
+ * Interface for mapping a X509 certificate to a LDAP entry
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapEncryptCertPublisher implements ILdapPublisher, IExtendedPluginInfo {
+ public static final String LDAP_USERCERT_ATTR = "userCertificate;binary";
+ public static final String PROP_REVOKE_CERT = "revokeCert";
+
+ protected String mCertAttr = LDAP_USERCERT_ATTR;
+ private ILogger mLogger = CMS.getLogger();
+ private IConfigStore mConfig = null;
+ private boolean mInited = false;
+ private boolean mRevokeCert;
+
+ public LdapEncryptCertPublisher() {
+ }
+
+ public String getImplName() {
+ return "LdapEncryptCertPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapEncryptCertPublisher";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ "certAttr;string;LDAP attribute in which to store the certificate",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-usercertpublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin knows how to publish user certificates"
+ };
+
+ return params;
+
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ return v;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCertAttr = mConfig.getString("certAttr", LDAP_USERCERT_ATTR);
+ mRevokeCert = mConfig.getBoolean(PROP_REVOKE_CERT, true);
+ mInited = true;
+ }
+
+ public LdapEncryptCertPublisher(String certAttr) {
+ mCertAttr = certAttr;
+ }
+
+ /**
+ * publish a user certificate
+ * Adds the cert to the multi-valued certificate attribute as a
+ * DER encoded binary blob. Does not check if cert already exists.
+ *
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the certificate
+ * @param certObj the certificate object.
+ */
+ public void publish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (conn == null)
+ return;
+
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ log(ILogger.LL_INFO, "Publishing " + cert);
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ // check if cert already exists.
+ LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mCertAttr }, false);
+ LDAPEntry entry = res.next();
+ LDAPAttribute attr = getModificationAttribute(entry.getAttribute(mCertAttr), certEnc);
+
+ if (attr == null) {
+ log(ILogger.LL_INFO, "publish: " + dn + " already has cert.");
+ return;
+ }
+
+ // publish
+ LDAPModification mod = new LDAPModification(LDAPModification.REPLACE, attr);
+
+ conn.modify(dn, mod);
+ } catch (CertificateEncodingException e) {
+ CMS.debug("LdapEncryptCertPublisher: error in publish: " + e.toString());
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ /**
+ * unpublish a user certificate
+ * deletes the certificate from the list of certificates.
+ * does not check if certificate is already there.
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ // check if cert already deleted.
+ LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mCertAttr }, false);
+ LDAPEntry entry = res.next();
+
+ if (!ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) {
+ log(ILogger.LL_INFO, dn + " already has not cert");
+ return;
+ }
+
+ LDAPModification mod = new LDAPModification(LDAPModification.DELETE,
+ new LDAPAttribute(mCertAttr, certEnc));
+
+ conn.modify(dn, mod);
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapUserCertPublisher: " + msg);
+ }
+
+ public LDAPAttribute getModificationAttribute(
+ LDAPAttribute attr, byte[] bval) {
+
+ LDAPAttribute at = new LDAPAttribute(attr.getName(), bval);
+ if (at == null) {
+ return at;
+ }
+
+ // determine if the given cert is a signing or an encryption
+ // certificate
+ X509CertImpl thisCert = null;
+
+ try {
+ thisCert = new X509CertImpl(bval);
+ } catch (Exception e) {
+ }
+ if (thisCert == null) {
+ return at;
+ }
+
+ Enumeration vals = attr.getByteValues();
+ byte[] val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (byte[]) vals.nextElement();
+ try {
+ X509CertImpl cert = new X509CertImpl(val);
+
+ log(ILogger.LL_INFO, "Checking " + cert);
+ if (CMS.isEncryptionCert(thisCert) &&
+ CMS.isEncryptionCert(cert)) {
+ // skip
+ log(ILogger.LL_INFO, "SKIP ENCRYPTION " + cert);
+ revokeCert(cert);
+ } else if (CMS.isSigningCert(thisCert) &&
+ CMS.isSigningCert(cert)) {
+ // skip
+ log(ILogger.LL_INFO, "SKIP SIGNING " + cert);
+ revokeCert(cert);
+ } else {
+ at.addValue(val);
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_CHECK_FAILED", e.toString()));
+ }
+ }
+ return at;
+ }
+
+ private RevokedCertImpl formCRLEntry(
+ BigInteger serialNo, RevocationReason reason)
+ throws EBaseException {
+ CRLReasonExtension reasonExt = new CRLReasonExtension(reason);
+ CRLExtensions crlentryexts = new CRLExtensions();
+
+ try {
+ crlentryexts.set(CRLReasonExtension.NAME, reasonExt);
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_SET_CRL_REASON", reason.toString(), e.toString()));
+
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_INTERNAL_ERROR", e.toString()));
+ }
+ RevokedCertImpl crlentry =
+ new RevokedCertImpl(serialNo, new Date(), crlentryexts);
+
+ return crlentry;
+ }
+
+ private void revokeCert(X509CertImpl cert)
+ throws EBaseException {
+ try {
+ if (mConfig.getBoolean(PROP_REVOKE_CERT, true) == false) {
+ return;
+ }
+ } catch (EBaseException e) {
+ return;
+ }
+ BigInteger serialNum = cert.getSerialNumber();
+ // need to revoke certificate also
+ ICertificateAuthority ca = (ICertificateAuthority)
+ CMS.getSubsystem("ca");
+ ICAService service = (ICAService) ca.getCAService();
+ RevokedCertImpl crlEntry = formCRLEntry(
+ serialNum, RevocationReason.KEY_COMPROMISE);
+
+ service.revokeCert(crlEntry);
+ }
+
+ /**
+ * checks if a byte attribute has a certain value.
+ */
+ public static boolean ByteValueExists(LDAPAttribute attr, byte[] bval) {
+ if (attr == null) {
+ return false;
+ }
+ Enumeration vals = attr.getByteValues();
+ byte[] val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (byte[]) vals.nextElement();
+ if (Utils.byteArraysAreEqual(val, bval)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * checks if a attribute has a string value.
+ */
+ public static boolean StringValueExists(LDAPAttribute attr, String sval) {
+ if (attr == null) {
+ return false;
+ }
+ Enumeration vals = attr.getStringValues();
+ String val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (String) vals.nextElement();
+ if (val.equalsIgnoreCase(sval)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java
new file mode 100644
index 000000000..fbc5cf6d1
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/LdapUserCertPublisher.java
@@ -0,0 +1,315 @@
+// --- 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.cms.publish.publishers;
+
+
+import netscape.ldap.*;
+import java.security.cert.*;
+import java.util.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+
+
+/**
+ * Interface for mapping a X509 certificate to a LDAP entry
+ *
+ * @version $Revision$, $Date$
+ */
+public class LdapUserCertPublisher implements ILdapPublisher, IExtendedPluginInfo {
+ public static final String LDAP_USERCERT_ATTR = "userCertificate;binary";
+
+ protected String mCertAttr = LDAP_USERCERT_ATTR;
+ private ILogger mLogger = CMS.getLogger();
+ private IConfigStore mConfig = null;
+ private boolean mInited = false;
+
+ public LdapUserCertPublisher() {
+ }
+
+ public String getImplName() {
+ return "LdapUserCertPublisher";
+ }
+
+ public String getDescription() {
+ return "LdapUserCertPublisher";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ "certAttr;string;LDAP attribute in which to store the certificate",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-usercertpublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This plugin knows how to publish user certificates"
+ };
+
+ return params;
+
+ }
+
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ return v;
+ }
+
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ v.addElement("certAttr=" + mCertAttr);
+ return v;
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void init(IConfigStore config)
+ throws EBaseException {
+ if (mInited)
+ return;
+ mConfig = config;
+ mCertAttr = mConfig.getString("certAttr", LDAP_USERCERT_ATTR);
+ mInited = true;
+ }
+
+ public LdapUserCertPublisher(String certAttr) {
+ mCertAttr = certAttr;
+ }
+
+ /**
+ * publish a user certificate
+ * Adds the cert to the multi-valued certificate attribute as a
+ * DER encoded binary blob. Does not check if cert already exists.
+ *
+ * @param conn the LDAP connection
+ * @param dn dn of the entry to publish the certificate
+ * @param certObj the certificate object.
+ */
+ public void publish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+ if (conn == null)
+ return;
+
+ // Bugscape #56124 - support multiple publishing directory
+ // see if we should create local connection
+ LDAPConnection altConn = null;
+ try {
+ String host = mConfig.getString("host", null);
+ String port = mConfig.getString("port", null);
+ if (host != null && port != null) {
+ int portVal = Integer.parseInt(port);
+ int version = Integer.parseInt(mConfig.getString("version", "2"));
+ String cert_nick = mConfig.getString("clientCertNickname", null);
+ LDAPSSLSocketFactoryExt sslSocket = null;
+ if (cert_nick != null) {
+ sslSocket = CMS.getLdapJssSSLSocketFactory(cert_nick);
+ }
+ String mgr_dn = mConfig.getString("bindDN", null);
+ String mgr_pwd = mConfig.getString("bindPWD", null);
+
+ altConn = CMS.getBoundConnection(host, portVal,
+ version,
+ sslSocket, mgr_dn, mgr_pwd);
+ conn = altConn;
+ }
+ } catch (LDAPException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ } catch (EBaseException e) {
+ CMS.debug("Failed to create alt connection " + e);
+ }
+
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ boolean deleteCert = false;
+ try {
+ deleteCert = mConfig.getBoolean("deleteCert", false);
+ } catch (Exception e) {
+ }
+
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ // check if cert already exists.
+ LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mCertAttr }, false);
+ LDAPEntry entry = res.next();
+
+ if (ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) {
+ log(ILogger.LL_INFO, "publish: " + dn + " already has cert.");
+ return;
+ }
+
+ // publish
+ LDAPModification mod = null;
+ if (deleteCert) {
+ mod = new LDAPModification(LDAPModification.REPLACE,
+ new LDAPAttribute(mCertAttr, certEnc));
+ } else {
+ mod = new LDAPModification(LDAPModification.ADD,
+ new LDAPAttribute(mCertAttr, certEnc));
+ }
+
+ conn.modify(dn, mod);
+
+ // log a successful message to the "transactions" log
+ mLogger.log( ILogger.EV_AUDIT,
+ ILogger.S_LDAP,
+ ILogger.LL_INFO,
+ AuditFormat.LDAP_PUBLISHED_FORMAT,
+ new Object[] { "LdapUserCertPublisher",
+ cert.getSerialNumber().toString(16),
+ cert.getSubjectDN() } );
+ } catch (CertificateEncodingException e) {
+ CMS.debug("LdapUserCertPublisher: error in publish: " + e.toString());
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_PUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_PUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ } finally {
+ if (altConn != null) {
+ try {
+ altConn.disconnect();
+ } catch (LDAPException e) {
+ // safely ignored
+ }
+ }
+ }
+ return;
+ }
+
+ /**
+ * unpublish a user certificate
+ * deletes the certificate from the list of certificates.
+ * does not check if certificate is already there.
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object certObj)
+ throws ELdapException {
+
+ boolean disableUnpublish = false;
+ try {
+ disableUnpublish = mConfig.getBoolean("disableUnpublish", false);
+ } catch (Exception e) {
+ }
+
+ if (disableUnpublish) {
+ CMS.debug("UserCertPublisher: disable unpublish");
+ return;
+ }
+
+ if (!(certObj instanceof X509Certificate))
+ throw new IllegalArgumentException("Illegal arg to publish");
+
+ X509Certificate cert = (X509Certificate) certObj;
+
+ try {
+ byte[] certEnc = cert.getEncoded();
+
+ // check if cert already deleted.
+ LDAPSearchResults res = conn.search(dn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mCertAttr }, false);
+ LDAPEntry entry = res.next();
+
+ if (!ByteValueExists(entry.getAttribute(mCertAttr), certEnc)) {
+ log(ILogger.LL_INFO, dn + " already has not cert");
+ return;
+ }
+
+ LDAPModification mod = new LDAPModification(LDAPModification.DELETE,
+ new LDAPAttribute(mCertAttr, certEnc));
+
+ conn.modify(dn, mod);
+ } catch (CertificateEncodingException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR", e.toString()));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_GET_DER_ENCODED_CERT_FAILED", e.toString()));
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.UNAVAILABLE) {
+ // need to intercept this because message from LDAP is
+ // "DSA is unavailable" which confuses with DSA PKI.
+ log(ILogger.LL_FAILURE,
+ CMS.getLogMessage("PUBLISH_NO_LDAP_SERVER"));
+ throw new ELdapServerDownException(CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_UNPUBLISH_ERROR"));
+ throw new ELdapException(CMS.getUserMessage("CMS_LDAP_UNPUBLISH_USERCERT_ERROR", e.toString()));
+ }
+ }
+ return;
+ }
+
+ private void log(int level, String msg) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_LDAP, level,
+ "LdapUserCertPublisher: " + msg);
+ }
+
+ /**
+ * checks if a byte attribute has a certain value.
+ */
+ public static boolean ByteValueExists(LDAPAttribute attr, byte[] bval) {
+ if (attr == null) {
+ return false;
+ }
+ Enumeration vals = attr.getByteValues();
+ byte[] val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (byte[]) vals.nextElement();
+ if (val.length == 0)
+ continue;
+ if (Utils.byteArraysAreEqual(val, bval)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * checks if a attribute has a string value.
+ */
+ public static boolean StringValueExists(LDAPAttribute attr, String sval) {
+ if (attr == null) {
+ return false;
+ }
+ Enumeration vals = attr.getStringValues();
+ String val = null;
+
+ while (vals.hasMoreElements()) {
+ val = (String) vals.nextElement();
+ if (val.equalsIgnoreCase(sval)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java b/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java
new file mode 100644
index 000000000..846ea7c48
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/OCSPPublisher.java
@@ -0,0 +1,351 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.net.*;
+import java.math.*;
+import java.io.*;
+import java.security.cert.*;
+import java.util.*;
+import netscape.ldap.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.logging.*;
+import org.mozilla.jss.ssl.*;
+import org.mozilla.jss.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.publish.*;
+import com.netscape.cmsutil.http.*;
+
+
+/**
+ * This publisher writes certificate and CRL into
+ * a directory.
+ *
+ * @version $Revision$, $Date$
+ */
+public class OCSPPublisher implements ILdapPublisher, IExtendedPluginInfo {
+ private static final String PROP_HOST = "host";
+ private static final String PROP_PORT = "port";
+ private static final String PROP_PATH = "path";
+ private static final String PROP_NICK = "nickName";
+ private static final String PROP_CLIENT_AUTH_ENABLE = "enableClientAuth";
+
+ private IConfigStore mConfig = null;
+ private String mHost = null;
+ private String mPort = null;
+ private String mPath = null;
+ private String mNickname = null;
+ private boolean mClientAuthEnabled = true;
+ private ILogger mLogger = CMS.getLogger();
+
+ /**
+ * Returns the implementation name.
+ */
+ public String getImplName() {
+ return "OCSPPublisher";
+ }
+
+ /**
+ * Returns the description of the ldap publisher.
+ */
+ public String getDescription() {
+ return "This publisher writes the CRL to CMS's OCSP server.";
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] params = {
+ PROP_HOST + ";string;Host of CMS's OCSP Secure agent service",
+ PROP_PORT + ";string;Port of CMS's OCSP Secure agent service",
+ PROP_PATH + ";string;URI of CMS's OCSP Secure agent service",
+ PROP_NICK + ";string;Nickname of cert used for client authentication",
+ PROP_CLIENT_AUTH_ENABLE + ";boolean;Client Authentication enabled",
+ IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-ldappublish-publisher-ocsppublisher",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";Publishes CRLs to a Online Certificate Status Manager, an OCSP responder provided by CMS."
+ };
+
+ return params;
+ }
+
+ /**
+ * Returns the current instance parameters.
+ */
+ public Vector getInstanceParams() {
+ Vector v = new Vector();
+ String host = "";
+ String port = "";
+ String path = "";
+ String nickname = "";
+ String clientAuthEnabled = "";
+
+ try {
+ host = mConfig.getString(PROP_HOST);
+ } catch (EBaseException e) {
+ }
+ v.addElement(PROP_HOST + "=" + host);
+ try {
+ port = mConfig.getString(PROP_PORT);
+ } catch (EBaseException e) {
+ }
+ v.addElement(PROP_PORT + "=" + port);
+ try {
+ path = mConfig.getString(PROP_PATH);
+ } catch (EBaseException e) {
+ }
+ v.addElement(PROP_PATH + "=" + path);
+ try {
+ nickname = mConfig.getString(PROP_NICK);
+ } catch (EBaseException e) {
+ }
+ v.addElement(PROP_NICK + "=" + nickname);
+ try {
+ clientAuthEnabled = mConfig.getString(PROP_CLIENT_AUTH_ENABLE);
+ } catch (EBaseException e) {
+ }
+ v.addElement(PROP_CLIENT_AUTH_ENABLE + "=" + clientAuthEnabled);
+ return v;
+ }
+
+ /**
+ * Returns the initial default parameters.
+ */
+ public Vector getDefaultParams() {
+ Vector v = new Vector();
+
+ IConfigStore config = CMS.getConfigStore();
+ String nickname = "";
+ // get subsystem cert nickname as default for client auth
+ try {
+ nickname = config.getString("ca.subsystem.nickname", "");
+ String tokenname = config.getString("ca.subsystem.tokenname", "");
+ if (!tokenname.equals("internal") && !tokenname.equals("Internal Key Storage Token"))
+ nickname = tokenname+":"+nickname;
+ } catch (Exception e) {
+ }
+
+
+ v.addElement(PROP_HOST + "=");
+ v.addElement(PROP_PORT + "=");
+ v.addElement(PROP_PATH + "=/ocsp/agent/ocsp/addCRL");
+ v.addElement(PROP_CLIENT_AUTH_ENABLE + "=true");
+ v.addElement(PROP_NICK + "=" + nickname);
+ return v;
+ }
+
+ /**
+ * Initializes this plugin.
+ */
+ public void init(IConfigStore config) {
+ mConfig = config;
+ try {
+ mHost = mConfig.getString(PROP_HOST, "");
+ mPort = mConfig.getString(PROP_PORT, "");
+ mPath = mConfig.getString(PROP_PATH, "");
+ mNickname = mConfig.getString(PROP_NICK, "");
+ mClientAuthEnabled = mConfig.getBoolean(PROP_CLIENT_AUTH_ENABLE, true);
+ } catch (EBaseException e) {
+ }
+ }
+
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ protected Socket Connect(String host, boolean secure, JssSSLSocketFactory factory)
+ {
+ Socket socket = null;
+ StringTokenizer st = new StringTokenizer(host, " ");
+ while (st.hasMoreTokens()) {
+ String hp = st.nextToken(); // host:port
+ StringTokenizer st1 = new StringTokenizer(hp, ":");
+ String h = st1.nextToken();
+ int p = Integer.parseInt(st1.nextToken());
+ try {
+ if (secure) {
+ socket = factory.makeSocket(h, p);
+ } else {
+ socket = new Socket(h, p);
+ }
+ return socket;
+ } catch (Exception e) {
+ }
+ try {
+ Thread.sleep(5000); // 5 seconds delay
+ } catch (Exception e) {
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Publishs a object to the ldap directory.
+ *
+ * @param conn a Ldap connection
+ * (null if LDAP publishing is not enabled)
+ * @param dn dn of the ldap entry to publish cert
+ * (null if LDAP publishing is not enabled)
+ * @param object object to publish
+ * (java.security.cert.X509Certificate or,
+ * java.security.cert.X509CRL)
+ */
+ public synchronized void publish(LDAPConnection conn, String dn, Object object)
+ throws ELdapException {
+ try {
+ if (!(object instanceof X509CRL))
+ return;
+ X509CRL crl = (X509CRL) object;
+
+ // talk to agent port of CMS
+
+ // open the connection and prepare it to POST
+ boolean secure = true;
+
+ String host = mHost;
+ int port = Integer.parseInt(mPort);
+ String path = mPath;
+
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_INFO, "OCSPPublisher: " +
+ "Host='" + host + "' Port='" + port +
+ "' URL='" + path + "'");
+ CMS.debug("OCSPPublisher: " +
+ "Host='" + host + "' Port='" + port +
+ "' URL='" + path + "'");
+
+ StringBuffer query = new StringBuffer();
+ query.append("crl=");
+ query.append(URLEncoder.encode("-----BEGIN CERTIFICATE REVOCATION LIST-----\n"));
+ query.append(URLEncoder.encode(CMS.BtoA(crl.getEncoded())));
+ query.append(URLEncoder.encode("\n-----END CERTIFICATE REVOCATION LIST-----"));
+ query.append("&noui=true");
+
+ Socket socket = null;
+ JssSSLSocketFactory factory;
+
+ if (mClientAuthEnabled) {
+ factory = new JssSSLSocketFactory(mNickname);
+ } else {
+ factory = new JssSSLSocketFactory();
+ }
+
+ if (mHost != null && mHost.indexOf(' ') != -1) {
+ // support failover hosts configuration
+ // host parameter can be
+ // "directory.knowledge.com:1050 people.catalog.com 199.254.1.2"
+ do {
+ socket = Connect(mHost, secure, factory);
+ } while (socket == null);
+ } else {
+ if (secure) {
+ socket = factory.makeSocket(host, port);
+ } else {
+ socket = new Socket(host, port);
+ }
+ }
+
+ if( socket == null ) {
+ CMS.debug( "OCSPPublisher::publish() - socket is null!" );
+ throw new ELdapException( "socket is null" );
+ }
+
+ // use HttpRequest and POST
+ HttpRequest httpReq = new HttpRequest();
+
+ httpReq.setMethod("POST");
+ httpReq.setURI(path);
+ httpReq.setHeader("Connection", "Keep-Alive");
+
+ httpReq.setHeader("Content-Type",
+ "application/x-www-form-urlencoded");
+ httpReq.setHeader("Content-Transfer-Encoding", "7bit");
+
+ httpReq.setHeader("Content-Length",
+ Integer.toString(query.length()));
+ httpReq.setContent(query.toString());
+ OutputStream os = socket.getOutputStream();
+ OutputStreamWriter outputStreamWriter = new OutputStreamWriter(os, "UTF8");
+
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_INFO, "OCSPPublisher: start sending CRL");
+ long startTime = CMS.getCurrentDate().getTime();
+ CMS.debug("OCSPPublisher: start CRL sending startTime=" + startTime);
+ httpReq.write(outputStreamWriter);
+ long endTime = CMS.getCurrentDate().getTime();
+ CMS.debug("OCSPPublisher: done CRL sending endTime=" + endTime + " diff=" + (endTime - startTime));
+
+ // Read the response
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_INFO, "OCSPPublisher: start getting response");
+ DataInputStream dis = new DataInputStream(socket.getInputStream());
+ String nextline;
+ String line = "";
+ String error = "";
+ boolean status = false;
+
+ while ((nextline = dis.readLine()) != null) {
+ if (nextline.startsWith("status=")) {
+ if (nextline.substring(7, nextline.length()).equals("0")) {
+ status = true;
+ }
+ }
+ if (nextline.startsWith("error=")) {
+ error = nextline.substring(6, nextline.length());
+ }
+ }
+ dis.close();
+ if (status) {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_INFO, "OCSPPublisher: successful");
+ } else {
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_INFO, "OCSPPublisher: failed - " + error);
+ }
+
+ } catch (IOException e) {
+ CMS.debug("OCSPPublisher: publish failed " + e.toString());
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString()));
+ } catch (CRLException e) {
+ CMS.debug("OCSPPublisher: publish failed " + e.toString());
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString()));
+ } catch (Exception e) {
+ CMS.debug("OCSPPublisher: publish failed " + e.toString());
+ mLogger.log(ILogger.EV_SYSTEM, ILogger.S_OTHER,
+ ILogger.LL_FAILURE, CMS.getLogMessage("PUBLISH_OCSP_PUBLISHER_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * Unpublishs a object to the ldap directory.
+ *
+ * @param conn the Ldap connection
+ * (null if LDAP publishing is not enabled)
+ * @param dn dn of the ldap entry to unpublish cert
+ * (null if LDAP publishing is not enabled)
+ * @param object object to unpublish
+ * (java.security.cert.X509Certificate)
+ */
+ public void unpublish(LDAPConnection conn, String dn, Object object)
+ throws ELdapException {
+ // NOT USED
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java b/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java
new file mode 100644
index 000000000..358a762b3
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/publish/publishers/Utils.java
@@ -0,0 +1,131 @@
+// --- 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.cms.publish.publishers;
+
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+
+/**
+ * Publisher utility class.
+ *
+ * @version $Revision$, $Date$
+ */
+public class Utils {
+ public static void checkHost(String hostname) throws UnknownHostException {
+ InetAddress addr = InetAddress.getByName(hostname);
+ }
+
+ public static void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] buf = new byte[4096];
+ int len;
+
+ while ((len = in.read(buf)) != -1) {
+ out.write(buf, 0, len);
+ }
+ }
+
+ public static void copyStream(BufferedReader in, OutputStreamWriter out) throws IOException {
+ char[] buf = new char[4096];
+ int len;
+
+ while ((len = in.read(buf)) != -1) {
+ out.write(buf, 0, len);
+ }
+ }
+
+ /// Sorts an array of Strings.
+ // Java currently has no general sort function. Sorting Strings is
+ // common enough that it's worth making a special case.
+ public static void sortStrings(String[] strings) {
+ // Just does a bubblesort.
+ for (int i = 0; i < strings.length - 1; ++i) {
+ for (int j = i + 1; j < strings.length; ++j) {
+ if (strings[i].compareTo(strings[j]) > 0) {
+ String t = strings[i];
+
+ strings[i] = strings[j];
+ strings[j] = t;
+ }
+ }
+ }
+ }
+
+ /// Returns a date string formatted in Unix ls style - if it's within
+ // six months of now, Mmm dd hh:ss, else Mmm dd yyyy.
+ public static String lsDateStr(Date date) {
+ long dateTime = date.getTime();
+
+ if (dateTime == -1L)
+ return "------------";
+ long nowTime = System.currentTimeMillis();
+ SimpleDateFormat formatter = new SimpleDateFormat();
+
+ if (Math.abs(nowTime - dateTime) < 183L * 24L * 60L * 60L * 1000L)
+ formatter.applyPattern("MMM dd hh:ss");
+ else
+ formatter.applyPattern("MMM dd yyyy");
+ return formatter.format(date);
+ }
+
+ /**
+ * compares contents two byte arrays returning true if exactly same.
+ */
+ static public boolean byteArraysAreEqual(byte[] a, byte[] b) {
+ if (a.length != b.length)
+ return false;
+ for (int i = 0; i < a.length; i++) {
+ if (a[i] != b[i])
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * strips out double quotes around String parameter
+ * @param s the string potentially bracketed with double quotes
+ * @return string stripped of surrounding double quotes
+ */
+ public static String stripQuotes(String s) {
+ if (s == null) {
+ return s;
+ }
+
+ if ((s.startsWith("\"")) && (s.endsWith("\""))) {
+ return (s.substring(1, (s.length() - 1)));
+ }
+
+ return s;
+ }
+
+ /**
+ * returns an array of strings from a vector of Strings
+ * there'll be trouble if the Vector contains something other
+ * than just Strings
+ */
+ public static String[] getStringArrayFromVector(Vector v) {
+ String s[] = new String[v.size()];
+
+ v.copyInto(s);
+ return s;
+ }
+
+}