summaryrefslogtreecommitdiffstats
path: root/pki/base/common/src/com/netscape/cms/authentication
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/common/src/com/netscape/cms/authentication')
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/AVAPattern.java542
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/AgentCertAuthentication.java325
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/CMCAuth.java1048
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/Crypt.java437
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/DNPattern.java211
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/DirBasedAuthentication.java657
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/FlatFileAuth.java678
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/HashAuthData.java117
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/HashAuthentication.java290
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/PortalEnroll.java458
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/RDNPattern.java227
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java353
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/SharedSecret.java36
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/TokenAuthentication.java298
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java199
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java270
-rw-r--r--pki/base/common/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java464
17 files changed, 6610 insertions, 0 deletions
diff --git a/pki/base/common/src/com/netscape/cms/authentication/AVAPattern.java b/pki/base/common/src/com/netscape/cms/authentication/AVAPattern.java
new file mode 100644
index 000000000..e4f700054
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/AVAPattern.java
@@ -0,0 +1,542 @@
+// --- 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.authentication;
+
+
+import java.util.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.apps.*;
+import java.io.*;
+import java.security.*;
+import netscape.security.x509.*;
+import netscape.security.util.*;
+import netscape.ldap.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a certificate
+ * subject name from ldap attributes and dn.<p>
+ *
+ * dnpattern is a string representing a subject name pattern to formulate from
+ * the directory attributes and entry dn. If empty or not set, the
+ * ldap entry DN will be used as the certificate subject name. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$attr" "." attrName [ "." attrNumber ] |
+ * name "=" "$dn" "." attrName [ "." attrNumber ] |
+ * "$dn" "." "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US </i>
+ * Ldap entry: dn: UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example2: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * <pre>
+ * Example3: <i>CN=$attr.cn, $rdn.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * followed by the second RDN in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example4: <i>CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN followed by the
+ * first 'ou' value in the user's entry. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * If an attribute or subject DN component does not exist the attribute
+ * is skipped.
+ *
+ * @version $Revision$, $Date$
+ */
+class AVAPattern {
+
+ /* the value type of the dn component */
+ public static final String TYPE_ATTR = "$attr";
+ public static final String TYPE_DN = "$dn";
+ public static final String TYPE_RDN = "$rdn";
+ public static final String TYPE_CONSTANT = "constant";
+
+ private static final char[] endChars = new char[] { '+', ',' };
+
+ private static final LdapV3DNStrConverter mLdapDNStrConverter =
+ new LdapV3DNStrConverter();
+
+ /* ldap attributes needed by this AVA (to retrieve from ldap) */
+ protected String[] mLdapAttrs = null;
+
+ /* value type */
+ protected String mType = null;
+
+ /* the attribute in the AVA pair */
+ protected String mAttr = null;
+
+ /* value - could be name of an ldap attribute or entry dn attribute. */
+ protected String mValue = null;
+
+ /* nth value of the ldap or dn attribute */
+ protected int mElement = 0;
+
+ protected String mTestDN = null;
+
+ public AVAPattern(String component)
+ throws EAuthException {
+ 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 EAuthException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws EAuthException {
+ 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 EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_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 EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_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 EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_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 $dn or $attr
+ try {
+ c = in.read();
+ //System.out.println("check $dn or $attr read "+(char)c);
+ } catch (IOException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ if (c == -1)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $dn or $attr in ava pattern"));
+ if (c == 'a') {
+ try {
+ if (in.read() != 't' ||
+ in.read() != 't' ||
+ in.read() != 'r' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $attr in ava pattern"));
+ } catch (IOException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ mType = TYPE_ATTR;
+ //System.out.println("---- mtype $attr");
+ } else if (c == 'd') {
+ try {
+ if (in.read() != 'n' ||
+ in.read() != '.')
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "expecting $dn in ava pattern"));
+ } catch (IOException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ mType = TYPE_DN;
+ //System.out.println("----- mtype $dn");
+ } else {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "unknown keyword. expecting $dn or $attr."));
+ }
+
+ // get attr name of 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"));
+ 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.getMessage()));
+ }
+
+ // get dn or attribute from ldap search.
+ 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 EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+
+ mValue = valueBuf.toString().trim();
+ if (mValue.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "$dn or $attr attribute name expected"));
+ //System.out.println("----- mValue "+mValue);
+
+ // get nth dn or attribute from ldap search.
+ if (c == '.') {
+ StringBuffer attrNumberBuf = new StringBuffer();
+
+ try {
+ while ((c = in.read()) != ',' && c != -1 && c != '+') {
+ //System.out.println("mElement read "+(char)c);
+ attrNumberBuf.append((char) c);
+ }
+ if (c != -1) // either ',' or '+'
+ in.unread(c); // pushback last , or +
+ } catch (IOException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ String attrNumber = attrNumberBuf.toString().trim();
+
+ if (attrNumber.length() == 0)
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "nth element $dn or $attr expected"));
+ try {
+ mElement = Integer.parseInt(attrNumber) - 1;
+ } catch (NumberFormatException e) {
+ throw new ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX",
+ "Invalid format in nth element $dn or $attr"));
+ }
+ }
+ //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);
+ 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 ECompSyntaxErr(CMS.getUserMessage("CMS_AUTHENTICATION_COMPONENT_SYNTAX", e.getMessage()));
+ }
+ 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.getMessage()));
+ }
+ }
+ }
+
+ public String formAVA(LDAPEntry entry)
+ throws EAuthException {
+ if (mType == TYPE_CONSTANT)
+ return mValue;
+
+ if (mType == TYPE_RDN) {
+ String dn = entry.getDN();
+
+ 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 (mType == TYPE_DN) {
+ String dn = entry.getDN();
+
+ 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 mAttr + "=" + value;
+ }
+
+ if (mType == TYPE_ATTR) {
+ LDAPAttribute ldapAttr = entry.getAttribute(mValue);
+
+ if (ldapAttr == null)
+ return null;
+ String value = null;
+ Enumeration ldapValues = ldapAttr.getStringValues();
+
+ for (int i = 0; ldapValues.hasMoreElements(); i++) {
+ String val = (String) ldapValues.nextElement();
+
+ if (i == mElement) {
+ value = val;
+ break;
+ }
+ }
+ if (value == null)
+ return null;
+ String v = escapeLdapString(value);
+
+ return mAttr + "=" + v;
+ }
+
+ return null;
+ }
+
+ private String escapeLdapString(String value) {
+ int len = value.length();
+ char[] c = new char[len];
+ char[] newc = new char[len * 2];
+
+ value.getChars(0, len, c, 0);
+ int j = 0;
+
+ for (int i = 0; i < c.length; i++) {
+ // escape special characters that directory does not.
+ if ((c[i] == ',' || c[i] == '=' || c[i] == '+' || c[i] == '<' ||
+ c[i] == '>' || c[i] == '#' || c[i] == ';')) {
+ if (i == 0 || c[i - 1] != '\\') {
+ newc[j++] = '\\';
+ newc[j++] = c[i];
+ }
+ } // escape "\"
+ else if (c[i] == '\\') {
+ int k = i + 1;
+
+ if (i == len - 1 ||
+ (c[k] == ',' || c[k] == '=' || c[k] == '+' || c[k] == '<' ||
+ c[k] == '>' || c[k] == '#' || c[k] == ';')) {
+ newc[j++] = '\\';
+ newc[j++] = c[i];
+ }
+ } // escape QUOTATION
+ else if (c[i] == '"') {
+ if ((i == 0 && c[len - 1] != '"') ||
+ (i == len - 1 && c[0] != '"') ||
+ (i > 0 && i < len - 1)) {
+ newc[j++] = '\\';
+ newc[j++] = c[i];
+ }
+ } else
+ newc[j++] = c[i];
+ }
+ return new String(newc, 0, j);
+ }
+
+ public String getLdapAttr() {
+ if (mType == TYPE_ATTR)
+ 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/authentication/AgentCertAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/AgentCertAuthentication.java
new file mode 100644
index 000000000..bef5e8c2a
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/AgentCertAuthentication.java
@@ -0,0 +1,325 @@
+// --- 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.authentication;
+
+
+import netscape.ldap.*;
+import java.util.*;
+import java.lang.Class;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.usrgrp.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.dbs.certdb.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.policy.*;
+
+import com.netscape.certsrv.ca.*;
+import com.netscape.certsrv.ra.*;
+import com.netscape.certsrv.kra.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Certificate server agent authentication.
+ * Maps a SSL client authenticate certificate to a user (agent) entry in the
+ * internal database.
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class AgentCertAuthentication implements IAuthManager,
+ IProfileAuthenticator {
+
+ /* result auth token attributes */
+ public static final String TOKEN_USERDN = "user";
+ public static final String TOKEN_USER_DN = "userdn";
+ public static final String TOKEN_USERID = "userid";
+ public static final String TOKEN_UID = "uid";
+ public static final String TOKEN_GROUP = "group";
+
+ /* required credentials */
+ public static final String CRED_CERT = IAuthManager.CRED_SSL_CLIENT_CERT;
+ protected String[] mRequiredCreds = { CRED_CERT };
+
+ /* config parameters to pass to console (none) */
+ protected static String[] mConfigParams = null;
+
+ private String mName = null;
+ private String mImplName = null;
+ private IConfigStore mConfig = null;
+
+ private IUGSubsystem mUGSub = null;
+ private ICertUserLocator mCULocator = null;
+ private ILogger mLogger = CMS.getLogger();
+
+ private IConfigStore mRevocationChecking = null;
+ private String mRequestor = null;
+
+ public AgentCertAuthentication() {
+ }
+
+ /**
+ * initializes the CertUserDBAuthentication auth manager
+ * <p>
+ * called by AuthSubsystem init() method, when initializing
+ * all available authentication managers.
+ * @param name The name of this authentication manager instance.
+ * @param implName The name of the authentication manager plugin.
+ * @param config The configuration store for this authentication manager.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+
+ mUGSub = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ mCULocator = mUGSub.getCertUserLocator();
+ }
+
+ /**
+ * Gets the name of this authentication manager.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the plugin name of authentication manager.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ public boolean isSSLClientRequired() {
+ return true;
+ }
+
+ /**
+ * authenticates user(agent) by certificate
+ * <p>
+ * called by other subsystems or their servlets to authenticate
+ * users (agents)
+ * @param authCred - authentication credential that contains
+ * an usrgrp.Certificates of the user (agent)
+ * @return the authentication token that contains the following
+ *
+ * @exception EMissingCredential If a required credential for this
+ * authentication manager is missing.
+ * @exception EInvalidCredentials If credentials cannot be authenticated.
+ * @exception EBaseException If an internal error occurred.
+ * @see com.netscape.certsrv.authentication.AuthToken
+ * @see com.netscape.certsrv.usrgrp.Certificates
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+
+ CMS.debug("AgentCertAuthentication: start");
+ CMS.debug("authenticator instance name is "+getName());
+
+ // force SSL handshake
+ SessionContext context = SessionContext.getExistingContext();
+ ISSLClientCertProvider provider = (ISSLClientCertProvider)
+ context.get("sslClientCertProvider");
+
+ if (provider == null) {
+ CMS.debug("AgentCertAuthentication: No SSL Client Cert Provider Found");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ CMS.debug("AgentCertAuthenticator: got provider");
+ CMS.debug("AgentCertAuthenticator: retrieving client certificate");
+ X509Certificate[] allCerts = provider.getClientCertificateChain();
+
+ if (allCerts == null) {
+ CMS.debug("AgentCertAuthentication: No SSL Client Certs Found");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ CMS.debug("AgentCertAuthenticator: got certificates");
+
+ // retreive certificate from socket
+ AuthToken authToken = new AuthToken(this);
+ X509Certificate[] x509Certs = allCerts;
+
+ // default certificate default has bugs in version
+ // version(3) is returned as 3, which should be 2
+ X509CertImpl ci[] = new X509CertImpl[x509Certs.length];
+
+ try {
+ for (int i = 0; i < x509Certs.length; i++) {
+ ci[i] = new X509CertImpl(x509Certs[i].getEncoded());
+ }
+ } catch (CertificateException e) {
+ CMS.debug(e.toString());
+ }
+
+ // check if certificate(s) is revoked
+ boolean checkRevocation = true;
+ try {
+ checkRevocation = mConfig.getBoolean("checkRevocation", true);
+ } catch (EBaseException e) {
+ // do nothing; default to true
+ }
+ if (checkRevocation) {
+ if (CMS.isRevoked(ci)) {
+ CMS.debug("AgentCertAuthentication: certificate revoked");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ }
+
+ // map cert to user
+ IUser user = null;
+ Certificates certs = new Certificates(ci);
+
+ try {
+ user = (IUser) mCULocator.locateUser(certs);
+ } catch (EUsrGrpException e) {
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ } catch (netscape.ldap.LDAPException e) {
+ throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR",
+ e.toString()));
+ }
+
+ // any unexpected error occurs like internal db down,
+ // UGSubsystem only returns null for user.
+ if (user == null) {
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // get group name from configuration file
+ IConfigStore sconfig = CMS.getConfigStore();
+ String groupname = "";
+ try {
+ groupname = sconfig.getString("auths.instance."+ getName() +".agentGroup",
+ "");
+ } catch (EBaseException ee) {
+ }
+
+ if (!groupname.equals("")) {
+ CMS.debug("check if "+user.getUserID()+" is in group "+groupname);
+ IUGSubsystem uggroup = (IUGSubsystem)CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ if (!uggroup.isMemberOf(user, groupname)) {
+ CMS.debug(user.getUserID()+" is not in this group "+groupname);
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHORIZATION_ERROR"));
+ }
+ }
+ authToken.set(TOKEN_USERDN, user.getUserDN());
+ authToken.set(TOKEN_USER_DN, user.getUserDN());
+ authToken.set(TOKEN_USERID, user.getUserID());
+ authToken.set(TOKEN_UID, user.getUserID());
+ authToken.set(TOKEN_GROUP, groupname);
+ authToken.set(CRED_CERT, certs);
+
+ CMS.debug("AgentCertAuthentication: authenticated " + user.getUserDN());
+
+ return authToken;
+ }
+
+ /**
+ * get the list of authentication credential attribute names
+ * required by this authentication manager. Generally used by
+ * the servlets that handle agent operations to authenticate its
+ * users. It calls this method to know which are the
+ * required credentials from the user (e.g. Javascript form data)
+ * @return attribute names in Vector
+ */
+ public String[] getRequiredCreds() {
+ return (mRequiredCreds);
+ }
+
+ /**
+ * get the list of configuration parameter names
+ * required by this authentication manager. Generally used by
+ * the Certificate Server Console to display the table for
+ * configuration purposes. CertUserDBAuthentication is currently not
+ * exposed in this case, so this method is not to be used.
+ * @return configuration parameter names in Hashtable of Vectors
+ * where each hashtable entry's key is the substore name, value is a
+ * Vector of parameter names. If no substore, the parameter name
+ * is the Hashtable key itself, with value same as key.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * prepare this authentication manager for shutdown.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * gets the configuretion substore used by this authentication
+ * manager
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ return null;
+ }
+
+ public boolean isValueWriteable(String name) {
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/CMCAuth.java b/pki/base/common/src/com/netscape/cms/authentication/CMCAuth.java
new file mode 100644
index 000000000..eb09e5b47
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/CMCAuth.java
@@ -0,0 +1,1048 @@
+// --- 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.authentication;
+
+
+///////////////////////
+// import statements //
+///////////////////////
+
+/* cert server imports */
+import com.netscape.cms.authentication.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.logging.ILogger;
+
+import com.netscape.cmsutil.util.*;
+import netscape.security.x509.*;
+
+/* java sdk imports */
+import java.io.*;
+import java.util.*;
+import java.util.Properties;
+import java.util.Vector;
+import com.netscape.certsrv.apps.*;
+import java.util.Hashtable;
+import java.security.MessageDigest;
+import java.security.PublicKey;
+
+import org.mozilla.jss.asn1.SET;
+import org.mozilla.jss.asn1.SEQUENCE;
+import org.mozilla.jss.asn1.INTEGER;
+import org.mozilla.jss.asn1.OCTET_STRING;
+import org.mozilla.jss.pkix.crmf.CertTemplate;
+import org.mozilla.jss.pkix.crmf.CertReqMsg;
+import org.mozilla.jss.pkix.crmf.CertRequest;
+import org.mozilla.jss.pkix.crmf.ChallengeResponseException;
+import org.mozilla.jss.pkix.primitive.SubjectPublicKeyInfo;
+import org.mozilla.jss.pkix.primitive.Name;
+import org.mozilla.jss.pkix.primitive.AlgorithmIdentifier;
+import org.mozilla.jss.asn1.InvalidBERException;
+import org.mozilla.jss.asn1.OBJECT_IDENTIFIER;
+import org.mozilla.jss.asn1.ANY;
+import org.mozilla.jss.pkix.cms.*;
+import org.mozilla.jss.pkix.cmc.*;
+import org.mozilla.jss.pkcs10.*;
+import org.mozilla.jss.crypto.*;
+import org.mozilla.jss.pkix.cert.Certificate;
+import org.mozilla.jss.pkix.cert.CertificateInfo;
+import org.mozilla.jss.asn1.ASN1Util;
+import org.mozilla.jss.pkcs11.*;
+
+import com.netscape.certsrv.usrgrp.*;
+
+import netscape.security.pkcs.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.property.*;
+import java.math.BigInteger;
+import org.mozilla.jss.CryptoManager;
+
+//import com.netscape.cmscore.util.*;
+//////////////////////
+// class definition //
+//////////////////////
+
+/**
+ * UID/CMC authentication plug-in
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class CMCAuth implements IAuthManager, IExtendedPluginInfo,
+ IProfileAuthenticator {
+
+ ////////////////////////
+ // default parameters //
+ ////////////////////////
+
+
+
+ /////////////////////////////
+ // IAuthManager parameters //
+ /////////////////////////////
+
+ /* authentication plug-in configuration store */
+ private IConfigStore mConfig;
+ private static final String HEADER = "-----BEGIN NEW CERTIFICATE REQUEST-----";
+ private static final String TRAILER = "-----END NEW CERTIFICATE REQUEST-----";
+ public static final String TOKEN_CERT_SERIAL = "certSerialToRevoke";
+ public static final String REASON_CODE = "reasonCode";
+ /* authentication plug-in name */
+ private String mImplName = null;
+
+ /* authentication plug-in instance name */
+ private String mName = null;
+
+ /* authentication plug-in fields */
+
+
+
+ /* Holds authentication 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.
+ */
+ protected static String[] mConfigParams =
+ new String[] {};
+
+ /* authentication plug-in values */
+
+ /* authentication plug-in properties */
+
+
+ /* required credentials to authenticate. UID and CMC are strings. */
+ public static final String CRED_CMC = "cmcRequest";
+
+ protected static String[] mRequiredCreds = {};
+
+ ////////////////////////////////////
+ // IExtendedPluginInfo parameters //
+ ////////////////////////////////////
+
+ /* Vector of extendedPluginInfo strings */
+ protected static Vector mExtendedPluginInfo = null;
+ //public static final String AGENT_AUTHMGR_ID = "agentAuthMgr";
+ //public static final String AGENT_PLUGIN_ID = "agentAuthPlugin";
+
+
+ /* actual help messages */
+ static {
+ mExtendedPluginInfo = new Vector();
+
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TEXT +
+ ";Authenticate the CMC request. The signer must be an agent. The \"Authentication Instance ID\" must be named \"CMCAuth\"");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-authentication");
+ }
+
+ ///////////////////////
+ // Logger parameters //
+ ///////////////////////
+
+ /* the system's logger */
+ private ILogger mLogger = CMS.getLogger();
+
+ /* signed audit parameters */
+ private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger();
+ private final static String SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE =
+ "enrollment";
+ private final static String SIGNED_AUDIT_REVOCATION_REQUEST_TYPE =
+ "revocation";
+ private final static String
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY =
+ "LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY_5";
+
+ /////////////////////
+ // default methods //
+ /////////////////////
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public CMCAuth() {
+ }
+
+ //////////////////////////
+ // IAuthManager methods //
+ //////////////////////////
+
+ /**
+ * Initializes the CMCAuth authentication plug-in.
+ * <p>
+ * @param name The name for this authentication plug-in instance.
+ * @param implName The name of the authentication plug-in.
+ * @param config - The configuration store for this instance.
+ * @exception EBaseException If an error occurs during initialization.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+
+ log(ILogger.LL_INFO, "Initialization complete!");
+ }
+
+ /**
+ * Authenticates user by their CMC;
+ * resulting AuthToken sets a TOKEN_SUBJECT for the subject name.
+ * <P>
+ *
+ * <ul>
+ * <li>signed.audit LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY
+ * used when CMC (agent-pre-signed) cert requests or revocation requests
+ * are submitted and signature is verified
+ * </ul>
+ * @param authCred Authentication credentials, CRED_UID and CRED_CMC.
+ * @return an AuthToken
+ * @exception com.netscape.certsrv.authentication.EMissingCredential
+ * If a required authentication credential is missing.
+ * @exception com.netscape.certsrv.authentication.EInvalidCredentials
+ * If credentials failed authentication.
+ * @exception com.netscape.certsrv.base.EBaseException
+ * If an internal error occurred.
+ * @see com.netscape.certsrv.authentication.AuthToken
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred) throws EMissingCredential, EInvalidCredentials, EBaseException {
+ String auditMessage = null;
+ String auditSubjectID = auditSubjectID();
+ String auditReqType = ILogger.UNIDENTIFIED;
+ String auditCertSubject = ILogger.UNIDENTIFIED;
+ String auditSignerInfo = ILogger.UNIDENTIFIED;
+
+ // ensure that any low-level exceptions are reported
+ // to the signed audit log and stored as failures
+ try {
+ // get the CMC.
+
+ Object argblock = (Object)(authCred.getArgBlock());
+ Object returnVal = null;
+ if (argblock == null) {
+ returnVal = authCred.get("cert_request");
+ if (returnVal == null)
+ returnVal = authCred.get(CRED_CMC);
+ } else {
+ returnVal = authCred.get("cert_request");
+ if (returnVal == null)
+ returnVal = authCred.getArgBlock().get(CRED_CMC);
+ }
+ String cmc = (String) returnVal;
+ if (cmc == null) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ throw new EMissingCredential(CMS.getUserMessage(
+ "CMS_AUTHENTICATION_NULL_CREDENTIAL",CRED_CMC));
+ }
+
+ if (cmc.equals("")) {
+ log(ILogger.LL_FAILURE,
+ "cmc : attempted login with empty CMC.");
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ throw new EInvalidCredentials(CMS.getUserMessage(
+ "CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // authenticate by checking CMC.
+
+ // everything OK.
+ // now formulate the certificate info.
+ // set the subject name at a minimum.
+ // set anything else like version, extensions, etc.
+ // if nothing except subject name is set the rest of
+ // cert info will be filled in by policies and CA defaults.
+
+ AuthToken authToken = new AuthToken(this);
+
+ try {
+ String asciiBASE64Blob;
+
+ int startIndex = cmc.indexOf(HEADER);
+ int endIndex = cmc.indexOf(TRAILER);
+ if (startIndex!= -1 && endIndex!=-1) {
+ startIndex = startIndex + HEADER.length();
+ asciiBASE64Blob=cmc.substring(startIndex, endIndex);
+ }else
+ asciiBASE64Blob = cmc;
+
+
+ byte[] cmcBlob = CMS.AtoB(asciiBASE64Blob);
+ ByteArrayInputStream cmcBlobIn= new
+ ByteArrayInputStream(cmcBlob);
+
+ org.mozilla.jss.pkix.cms.ContentInfo cmcReq =
+ (org.mozilla.jss.pkix.cms.ContentInfo)
+ org.mozilla.jss.pkix.cms.ContentInfo.getTemplate().decode(
+ cmcBlobIn);
+
+ if(!cmcReq.getContentType().equals(
+ org.mozilla.jss.pkix.cms.ContentInfo.SIGNED_DATA) ||
+ !cmcReq.hasContent()) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ // throw new ECMSGWException(CMSGWResources.NO_CMC_CONTENT);
+
+ throw new EBaseException("NO_CMC_CONTENT");
+ }
+
+ SignedData cmcFullReq = (SignedData)
+ cmcReq.getInterpretedContent();
+
+ IConfigStore cmc_config = CMS.getConfigStore();
+ boolean checkSignerInfo =
+ cmc_config.getBoolean("cmc.signerInfo.verify", true);
+ String userid = "defUser";
+ String uid = "defUser";
+ if (checkSignerInfo) {
+ IAuthToken agentToken = verifySignerInfo(authToken,cmcFullReq);
+ userid = agentToken.getInString("userid");
+ uid = agentToken.getInString("cn");
+ } else {
+ CMS.debug("CMCAuth: authenticate() signerInfo verification bypassed");
+ }
+ // reset value of auditSignerInfo
+ if( uid != null ) {
+ auditSignerInfo = uid.trim();
+ }
+
+ EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
+
+ OBJECT_IDENTIFIER id = ci.getContentType();
+
+ if (!id.equals(OBJECT_IDENTIFIER.id_cct_PKIData) ||
+ !ci.hasContent()) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ // throw new ECMSGWException(
+ // CMSGWResources.NO_PKIDATA);
+
+ throw new EBaseException("NO_PKIDATA");
+ }
+
+ OCTET_STRING content = ci.getContent();
+
+ ByteArrayInputStream s = new
+ ByteArrayInputStream(content.toByteArray());
+ PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s);
+
+ SEQUENCE reqSequence = pkiData.getReqSequence();
+
+ int numReqs = reqSequence.size();
+
+ if (numReqs == 0) {
+ // revocation request
+
+ // reset value of auditReqType
+ auditReqType = SIGNED_AUDIT_REVOCATION_REQUEST_TYPE;
+
+ SEQUENCE controlSequence = pkiData.getControlSequence();
+ int controlSize = controlSequence.size();
+
+ if (controlSize > 0) {
+ for (int i = 0; i < controlSize; i++) {
+ TaggedAttribute taggedAttribute =
+ (TaggedAttribute) controlSequence.elementAt(i);
+ OBJECT_IDENTIFIER type = taggedAttribute.getType();
+
+ if( type.equals(
+ OBJECT_IDENTIFIER.id_cmc_revokeRequest)) {
+ // if( i ==1 ) {
+ // taggedAttribute.getType() ==
+ // OBJECT_IDENTIFIER.id_cmc_revokeRequest
+ // }
+
+ SET values = taggedAttribute.getValues();
+ int numVals = values.size();
+ BigInteger[] bigIntArray = null;
+
+ bigIntArray = new BigInteger[numVals];
+ for (int j = 0; j < numVals; j++) {
+ // serialNumber INTEGER
+
+ // SEQUENCE RevRequest = (SEQUENCE)
+ // values.elementAt(j);
+ byte[] encoded = ASN1Util.encode(
+ values.elementAt(j));
+ org.mozilla.jss.asn1.ASN1Template
+ template = new
+ org.mozilla.jss.pkix.cmmf.RevRequest.Template();
+ org.mozilla.jss.pkix.cmmf.RevRequest
+ revRequest =
+ (org.mozilla.jss.pkix.cmmf.RevRequest)
+ ASN1Util.decode(template, encoded);
+
+ // SEQUENCE RevRequest = (SEQUENCE)
+ // ASN1Util.decode(
+ // SEQUENCE.getTemplate(),
+ // ASN1Util.encode(
+ // values.elementAt(j)));
+
+ // SEQUENCE RevRequest =
+ // values.elementAt(j);
+ // int revReqSize = RevRequest.size();
+ // if( revReqSize > 3 ) {
+ // INTEGER serialNumber =
+ // new INTEGER((long)0);
+ // }
+
+ INTEGER temp = revRequest.getSerialNumber();
+ int temp2 = temp.intValue();
+
+ bigIntArray[j] = temp;
+ authToken.set(TOKEN_CERT_SERIAL,bigIntArray);
+
+ long reasonCode = revRequest.getReason().getValue();
+ Integer IntObject = Integer.valueOf((int)reasonCode);
+ authToken.set(REASON_CODE,IntObject);
+
+ authToken.set("uid",uid);
+ authToken.set("userid",userid);
+ }
+ }
+ }
+
+ }
+ } else {
+ // enrollment request
+
+ // reset value of auditReqType
+ auditReqType = SIGNED_AUDIT_ENROLLMENT_REQUEST_TYPE;
+
+ X509CertInfo[] certInfoArray = new X509CertInfo[numReqs];
+ String[] reqIdArray = new String[numReqs];
+
+ for (int i = 0; i < numReqs; i++) {
+ // decode message.
+ TaggedRequest taggedRequest =
+ (TaggedRequest) reqSequence.elementAt(i);
+
+ TaggedRequest.Type type = taggedRequest.getType();
+
+ if (type.equals(TaggedRequest.PKCS10)) {
+ CMS.debug("CMCAuth: in PKCS10");
+ TaggedCertificationRequest tcr =
+ taggedRequest.getTcr();
+ int p10Id = tcr.getBodyPartID().intValue();
+
+ reqIdArray[i] = String.valueOf(p10Id);
+
+ CertificationRequest p10 =
+ tcr.getCertificationRequest();
+
+ // transfer to sun class
+ ByteArrayOutputStream ostream =
+ new ByteArrayOutputStream();
+
+ p10.encode(ostream);
+ try {
+ PKCS10 pkcs10 =
+ new PKCS10(ostream.toByteArray());
+
+ // xxx do we need to do anything else?
+ X509CertInfo certInfo =
+ CMS.getDefaultX509CertInfo();
+
+ // fillPKCS10(certInfo,pkcs10,authToken,null);
+
+ // authToken.set(
+ // pkcs10.getSubjectPublicKeyInfo());
+
+ X500Name tempName = pkcs10.getSubjectName();
+
+ // reset value of auditCertSubject
+ if( tempName != null ) {
+ auditCertSubject =
+ tempName.toString().trim();
+ if( auditCertSubject.equals( "" ) ) {
+ auditCertSubject =
+ ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+ authToken.set(AuthToken.TOKEN_CERT_SUBJECT,
+ tempName.toString());
+ }
+
+ authToken.set("uid", uid);
+ authToken.set("userid", userid);
+
+ certInfoArray[i] = certInfo;
+ } catch (Exception e) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ //throw new ECMSGWException(
+ //CMSGWResources.ERROR_PKCS101, e.toString());
+
+ e.printStackTrace();
+ throw new EBaseException(e.toString());
+ }
+ } else if (type.equals(TaggedRequest.CRMF)) {
+
+ CMS.debug("CMCAuth: in CRMF");
+ try {
+ CertReqMsg crm =
+ taggedRequest.getCrm();
+ CertRequest certReq = crm.getCertReq();
+ INTEGER reqID = certReq.getCertReqId();
+ reqIdArray[i] = reqID.toString();
+ CertTemplate template = certReq.getCertTemplate();
+ Name name = template.getSubject();
+
+ // xxx do we need to do anything else?
+ X509CertInfo certInfo =
+ CMS.getDefaultX509CertInfo();
+
+ // reset value of auditCertSubject
+ if( name != null ) {
+ String ss = name.getRFC1485();
+
+ auditCertSubject = ss;
+ if( auditCertSubject.equals( "" ) ) {
+ auditCertSubject =
+ ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+ }
+
+ authToken.set(AuthToken.TOKEN_CERT_SUBJECT, ss);
+ authToken.set("uid", uid);
+ authToken.set("userid", userid);
+ }
+ certInfoArray[i] = certInfo;
+ } catch (Exception e) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ //throw new ECMSGWException(
+ //CMSGWResources.ERROR_PKCS101, e.toString());
+
+ e.printStackTrace();
+ throw new EBaseException(e.toString());
+ }
+ }
+
+ // authToken.set(AgentAuthentication.CRED_CERT, new
+ // com.netscape.certsrv.usrgrp.Certificates(
+ // x509Certs));
+ }
+ }
+ } catch (Exception e) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ //Debug.printStackTrace(e);
+ throw new EInvalidCredentials(CMS.getUserMessage(
+ "CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.SUCCESS,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ return authToken;
+ } catch( EMissingCredential eAudit1 ) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ // rethrow the specific exception to be handled later
+ throw eAudit1;
+ } catch( EInvalidCredentials eAudit2 ) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ // rethrow the specific exception to be handled later
+ throw eAudit2;
+ } catch( EBaseException eAudit3 ) {
+ // store a message in the signed audit log file
+ auditMessage = CMS.getLogMessage(
+ LOGGING_SIGNED_AUDIT_CMC_SIGNED_REQUEST_SIG_VERIFY,
+ auditSubjectID,
+ ILogger.FAILURE,
+ auditReqType,
+ auditCertSubject,
+ auditSignerInfo );
+
+ audit( auditMessage );
+
+ // rethrow the specific exception to be handled later
+ throw eAudit3;
+ }
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ * <p>
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * gets the configuration substore used by this authentication
+ * plug-in
+ * <p>
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * gets the plug-in name of this authentication plug-in.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ /**
+ * gets the name of this authentication plug-in instance
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * get the list of required credentials.
+ * <p>
+ * @return list of required credentials as strings.
+ */
+ public String[] getRequiredCreds() {
+ return (mRequiredCreds);
+ }
+
+ /**
+ * prepares for shutdown.
+ */
+ public void shutdown() {
+ }
+
+ /////////////////////////////////
+ // IExtendedPluginInfo methods //
+ /////////////////////////////////
+
+ /**
+ * Activate the help system.
+ * <p>
+ * @return help messages
+ */
+ public String[] getExtendedPluginInfo() {
+ CMS.debug("CMCAuth: getExtendedPluginInfo()");
+ String[] s = Utils.getStringArrayFromVector(mExtendedPluginInfo);
+
+ CMS.debug("CMCAuth: s.length = " + s.length);
+ for (int i = 0; i < s.length; i++) {
+ CMS.debug("" + i + " " + s[i]);
+ }
+ return s;
+ }
+
+ ////////////////////
+ // Logger methods //
+ ////////////////////
+
+ /**
+ * Logs a message for this class in the system log file.
+ * <p>
+ * @param level The log level.
+ * @param msg The message to log.
+ * @see com.netscape.certsrv.logging.ILogger
+ */
+ protected void log(int level, String msg) {
+ if (mLogger == null)
+ return;
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_AUTHENTICATION,
+ level, "CMC Authentication: " + msg);
+ }
+
+ protected IAuthToken verifySignerInfo(AuthToken authToken,SignedData cmcFullReq) throws EInvalidCredentials {
+
+ EncapsulatedContentInfo ci = cmcFullReq.getContentInfo();
+ OBJECT_IDENTIFIER id = ci.getContentType();
+ OCTET_STRING content = ci.getContent();
+
+ try {
+ ByteArrayInputStream s = new ByteArrayInputStream(content.toByteArray());
+ PKIData pkiData = (PKIData) (new PKIData.Template()).decode(s);
+
+ SET dais = cmcFullReq.getDigestAlgorithmIdentifiers();
+ int numDig = dais.size();
+ Hashtable digs = new Hashtable();
+
+ //if request key is used for signing, there MUST be only one signerInfo
+ //object in the signedData object.
+ for (int i = 0; i < numDig; i++) {
+ AlgorithmIdentifier dai =
+ (AlgorithmIdentifier) dais.elementAt(i);
+ String name =
+ DigestAlgorithm.fromOID(dai.getOID()).toString();
+
+ MessageDigest md =
+ MessageDigest.getInstance(name);
+
+ byte[] digest = md.digest(content.toByteArray());
+
+ digs.put(name, digest);
+ }
+
+ SET sis = cmcFullReq.getSignerInfos();
+ int numSis = sis.size();
+
+ for (int i = 0; i < numSis; i++) {
+ org.mozilla.jss.pkix.cms.SignerInfo si = (org.mozilla.jss.pkix.cms.SignerInfo) sis.elementAt(i);
+
+ String name = si.getDigestAlgorithm().toString();
+ byte[] digest = (byte[]) digs.get(name);
+
+ if (digest == null) {
+ MessageDigest md = MessageDigest.getInstance(name);
+ ByteArrayOutputStream ostream = new ByteArrayOutputStream();
+
+ pkiData.encode((OutputStream) ostream);
+ digest = md.digest(ostream.toByteArray());
+
+ }
+ // signed by previously certified signature key
+ SignerIdentifier sid = si.getSignerIdentifier();
+
+ if (sid.getType().equals(SignerIdentifier.ISSUER_AND_SERIALNUMBER)) {
+ IssuerAndSerialNumber issuerAndSerialNumber = sid.getIssuerAndSerialNumber();
+ // find from the certs in the signedData
+ java.security.cert.X509Certificate cert = null;
+
+ if (cmcFullReq.hasCertificates()) {
+ SET certs = cmcFullReq.getCertificates();
+ int numCerts = certs.size();
+ java.security.cert.X509Certificate[] x509Certs = new java.security.cert.X509Certificate[1];
+ byte[] certByteArray = new byte[0];
+ for (int j = 0; j < numCerts; j++) {
+ Certificate certJss = (Certificate) certs.elementAt(j);
+ CertificateInfo certI = certJss.getInfo();
+ Name issuer = certI.getIssuer();
+
+ byte[] issuerB = ASN1Util.encode(issuer);
+ INTEGER sn = certI.getSerialNumber();
+ // if this cert is the signer cert, not a cert in the chain
+ if (new String(issuerB).equals(new String(ASN1Util.encode(issuerAndSerialNumber.getIssuer())))
+ && sn.toString().equals(issuerAndSerialNumber.getSerialNumber().toString()) )
+ {
+ ByteArrayOutputStream os = new
+ ByteArrayOutputStream();
+
+ certJss.encode(os);
+ certByteArray = os.toByteArray();
+
+ X509CertImpl tempcert = new X509CertImpl(os.toByteArray());
+
+ cert = tempcert;
+ x509Certs[0] = cert;
+ // xxx validate the cert length
+
+ }
+ }
+ CMS.debug("CMCAuth: start checking signature");
+ if (cert == null) {
+ // find from certDB
+ CMS.debug("CMCAuth: verifying signature");
+ si.verify(digest, id);
+ } else {
+ PublicKey signKey = cert.getPublicKey();
+ PrivateKey.Type keyType = null;
+ String alg = signKey.getAlgorithm();
+
+ if (alg.equals("RSA")) {
+ keyType = PrivateKey.RSA;
+ } else if (alg.equals("DSA")) {
+ keyType = PrivateKey.DSA;
+ }
+ PK11PubKey pubK = PK11PubKey.fromRaw(keyType, ((X509Key) signKey).getKey());
+
+ CMS.debug("CMCAuth: verifying signature with public key");
+ si.verify(digest, id, pubK);
+ }
+ CMS.debug("CMCAuth: finished checking signature");
+ // verify signer's certificate using the revocator
+ CryptoManager cm = CryptoManager.getInstance();
+ if( ! cm.isCertValid( certByteArray, true,CryptoManager.CertUsage.SSLClient) )
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ // authenticate signer's certificate using the userdb
+ IAuthSubsystem authSS = (IAuthSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTH);
+
+ IAuthManager agentAuth = authSS.getAuthManager(IAuthSubsystem.CERTUSERDB_AUTHMGR_ID);//AGENT_AUTHMGR_ID);
+ IAuthCredentials agentCred = new com.netscape.certsrv.authentication.AuthCredentials();
+
+ agentCred.set(IAuthManager.CRED_SSL_CLIENT_CERT, x509Certs);
+
+ IAuthToken tempToken = agentAuth.authenticate(agentCred);
+ netscape.security.x509.X500Name tempPrincipal = (X500Name) x509Certs[0].getSubjectDN();
+ String CN = (String) tempPrincipal.getCommonName();//tempToken.get("userid");
+
+ BigInteger agentCertSerial = x509Certs[0].getSerialNumber();
+ authToken.set(IAuthManager.CRED_SSL_CLIENT_CERT,agentCertSerial.toString());
+ tempToken.set("cn",CN);
+ return tempToken;
+
+ }
+ // find from internaldb if it's ca. (ra does not have that.)
+ // find from internaldb usrgrp info
+
+ if (cert == null) {
+ // find from certDB
+ si.verify(digest, id);
+ } else {
+ PublicKey signKey = cert.getPublicKey();
+ PrivateKey.Type keyType = null;
+ String alg = signKey.getAlgorithm();
+
+ if (alg.equals("RSA")) {
+ keyType = PrivateKey.RSA;
+ } else if (alg.equals("DSA")) {
+ keyType = PrivateKey.DSA;
+ } else {
+ }
+ PK11PubKey pubK = PK11PubKey.fromRaw(keyType, ((X509Key) signKey).getKey());
+
+ si.verify(digest, id, pubK);
+ }
+
+ } //
+ }
+ }catch (InvalidBERException e) {
+ CMS.debug("CMCAuth: " + e.toString());
+ } catch (IOException e) {
+ CMS.debug("CMCAuth: " + e.toString());
+ } catch (Exception e) {
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ return (IAuthToken) null;
+
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ return null;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale)
+ {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_CMS_SIGN_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale)
+ {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_CMS_SIGN_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ Vector v = new Vector();
+ v.addElement("cert_request");
+ return v.elements();
+ }
+
+ public boolean isValueWriteable(String name) {
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ if (name.equals(CRED_CMC)) {
+ return new Descriptor(IDescriptor.STRING_LIST, null, null,
+ "CMC request");
+ }
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ request.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME,
+ token.getInString(AuthToken.TOKEN_CERT_SUBJECT));
+ }
+
+ public boolean isSSLClientRequired() {
+ return false;
+ }
+
+ /**
+ * Signed Audit Log
+ *
+ * This method is called to store messages to the signed audit log.
+ * <P>
+ *
+ * @param msg signed audit log message
+ */
+ private void audit(String msg) {
+ // in this case, do NOT strip preceding/trailing whitespace
+ // from passed-in String parameters
+
+ if (mSignedAuditLogger == null) {
+ return;
+ }
+
+ mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT,
+ null,
+ ILogger.S_SIGNED_AUDIT,
+ ILogger.LL_SECURITY,
+ msg);
+ }
+
+ /**
+ * Signed Audit Log Subject ID
+ *
+ * This method is called to obtain the "SubjectID" for
+ * a signed audit log message.
+ * <P>
+ *
+ * @return id string containing the signed audit log message SubjectID
+ */
+ private String auditSubjectID() {
+ // if no signed audit object exists, bail
+ if (mSignedAuditLogger == null) {
+ return null;
+ }
+
+ String subjectID = null;
+
+ // Initialize subjectID
+ SessionContext auditContext = SessionContext.getExistingContext();
+
+ if (auditContext != null) {
+ subjectID = (String)
+ auditContext.get(SessionContext.USER_ID);
+
+ if (subjectID != null) {
+ subjectID = subjectID.trim();
+ } else {
+ subjectID = ILogger.NONROLEUSER;
+ }
+ } else {
+ subjectID = ILogger.UNIDENTIFIED;
+ }
+
+ return subjectID;
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/Crypt.java b/pki/base/common/src/com/netscape/cms/authentication/Crypt.java
new file mode 100644
index 000000000..950120399
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/Crypt.java
@@ -0,0 +1,437 @@
+// --- 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.authentication;
+
+
+public class Crypt {
+ // Static data:
+ static byte[]
+ IP = // Initial permutation
+ {
+ 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7
+ },
+ FP = // Final permutation, FP = IP^(-1)
+ {
+ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25
+ },
+ // Permuted-choice 1 from the key bits to yield C and D.
+ // Note that bits 8,16... are left out:
+ // They are intended for a parity check.
+ PC1_C =
+ {
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36
+ },
+ PC1_D =
+ {
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+ },
+ shifts = // Sequence of shifts used for the key schedule.
+ {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+ },
+ // Permuted-choice 2, to pick out the bits from
+ // the CD array that generate the key schedule.
+ PC2_C =
+ {
+ 14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2
+ },
+ PC2_D =
+ {
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32
+ },
+ e2 = // The E-bit selection table. (see E below)
+ {
+ 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1
+ },
+ // P is a permutation on the selected combination of
+ // the current L and key.
+ P =
+ {
+ 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25
+ };
+ // The 8 selection functions. For some reason, they gave a 0-origin
+ // index, unlike everything else.
+ static byte[][] S =
+ {
+ {
+ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13
+ }, {
+ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9
+ }, {
+ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12
+ }, {
+ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14
+ }, {
+ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3
+ }, {
+ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13
+ }, {
+ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12
+ }, {
+ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
+ }
+ };
+
+ // Dynamic data:
+ byte[] C = new byte[28], // The C and D arrays used to
+ D = new byte[28], // calculate the key schedule.
+ E = new byte[48], // The E bit-selection table.
+ L = new byte[32], // The current block,
+ R = new byte[32], // divided into two halves.
+ tempL = new byte[32],
+ f = new byte[32],
+ preS = new byte[48]; // The combination of the key and
+ // the input, before selection.
+ // The key schedule. Generated from the key.
+ byte[][] KS = new byte[16][48];
+
+ // Object fields:
+ String Passwd, Salt, Encrypt;
+
+ // Public methods:
+ /**
+ * Create Crypt object with no passwd or salt set. Must use setPasswd()
+ * and setSalt() before getEncryptedPasswd().
+ */
+ public Crypt() {
+ Passwd = Salt = Encrypt = "";
+ }
+
+ /**
+ * Create a Crypt object with specified salt. Use setPasswd() before
+ * getEncryptedPasswd().
+ *
+ * @param salt the salt string for encryption
+ */
+ public Crypt(String salt) {
+ Passwd = "";
+ Salt = salt;
+ Encrypt = crypt();
+ }
+
+ /**
+ * Create a Crypt object with specified passwd and salt (often the
+ * already encypted passwd). Get the encrypted result with
+ * getEncryptedPasswd().
+ *
+ * @param passwd the passwd to encrypt
+ * @param salt the salt string for encryption
+ */
+ public Crypt(String passwd, String salt) {
+ Passwd = passwd;
+ Salt = salt;
+ Encrypt = crypt();
+ }
+
+ /**
+ * Retrieve the passwd string currently being encrypted.
+ *
+ * @return the current passwd string
+ */
+ public String getPasswd() {
+ return Passwd;
+ }
+
+ /**
+ * Retrieve the salt string currently being used for encryption.
+ *
+ * @return the current salt string
+ */
+ public String getSalt() {
+ return Salt;
+ }
+
+ /**
+ * Retrieve the resulting encrypted string from the current passwd and
+ * salt settings.
+ *
+ * @return the encrypted passwd
+ */
+ public String getEncryptedPasswd() {
+ return Encrypt;
+ }
+
+ /**
+ * Set a new passwd string for encryption. Use getEncryptedPasswd() to
+ * retrieve the new result.
+ *
+ * @param passwd the new passwd string
+ */
+ public void setPasswd(String passwd) {
+ Passwd = passwd;
+ Encrypt = crypt();
+ }
+
+ /**
+ * Set a new salt string for encryption. Use getEncryptedPasswd() to
+ * retrieve the new result.
+ *
+ * @param salt the new salt string
+ */
+ public void setSalt(String salt) {
+ Salt = salt;
+ Encrypt = crypt();
+ }
+
+ // Internal crypt methods:
+ String crypt() {
+ if (Salt.length() == 0) return "";
+ int i, j, pwi;
+ byte c, temp;
+ byte[] block = new byte[66],
+ iobuf = new byte[16],
+ salt = new byte[2],
+ pw = Passwd.getBytes(), //jdk1.1
+ saltbytes = Salt.getBytes(); //jdk1.1
+
+ // pw = new byte[Passwd.length()], //jdk1.0.2
+ // saltbytes = new byte[Salt.length()]; //jdk1.0.2
+ //Passwd.getBytes(0,Passwd.length(),pw,0); //jdk1.0.2
+ //Salt.getBytes(0,Salt.length(),saltbytes,0); //jdk1.0.2
+
+ salt[0] = saltbytes[0];
+ salt[1] = (saltbytes.length > 1) ? saltbytes[1] : 0;
+
+ for (i = 0; i < 66; i++)
+ block[i] = 0;
+
+ for (i = 0, pwi = 0; (pwi < pw.length) && (i < 64); pwi++, i++) {
+ for (j = 0; j < 7; j++, i++) {
+ block[i] = (byte) ((pw[pwi] >> (6 - j)) & 1);
+ }
+ }
+
+ setkey(block);
+
+ for (i = 0; i < 66; i++)
+ block[i] = 0;
+
+ for (i = 0; i < 2; i++) {
+ c = salt[i];
+ iobuf[i] = c;
+ if (c > 'Z') c -= 6;
+ if (c > '9') c -= 7;
+ c -= '.';
+ for (j = 0; j < 6; j++) {
+ if (((c >> j) & 1) != 0) {
+ temp = E[6 * i + j];
+ E[6 * i + j] = E[6 * i + j + 24];
+ E[6 * i + j + 24] = temp;
+ }
+ }
+ }
+
+ for (i = 0; i < 25; i++) {
+ encrypt(block, 0);
+ }
+
+ for (i = 0; i < 11; i++) {
+ c = 0;
+ for (j = 0; j < 6; j++) {
+ c <<= 1;
+ c |= block[6 * i + j];
+ }
+ c += '.';
+ if (c > '9') c += 7;
+ if (c > 'Z') c += 6;
+ iobuf[i + 2] = c;
+ }
+
+ iobuf[i + 2] = 0;
+ if (iobuf[1] == 0)
+ iobuf[1] = iobuf[0];
+
+ return new String(iobuf); //jdk1.1
+ //return new String(iobuf,0); //jdk1.0.2
+ }
+
+ void setkey(byte[] key) // Set up the key schedule from the key.
+ {
+ int i, j, k;
+ byte t;
+
+ // First, generate C and D by permuting the key. The low order bit
+ // of each 8-bit char is not used, so C and D are only 28 bits apiece.
+ for (i = 0; i < 28; i++) {
+ C[i] = key[PC1_C[i] - 1];
+ D[i] = key[PC1_D[i] - 1];
+ }
+
+ // To generate Ki, rotate C and D according to schedule
+ // and pick up a permutation using PC2.
+ for (i = 0; i < 16; i++) {
+ // rotate.
+ for (k = 0; k < shifts[i]; k++) {
+ t = C[0];
+ for (j = 0; j < 27; j++)
+ C[j] = C[j + 1];
+ C[27] = t;
+ t = D[0];
+ for (j = 0; j < 27; j++)
+ D[j] = D[j + 1];
+ D[27] = t;
+ }
+
+ // get Ki. Note C and D are concatenated.
+ for (j = 0; j < 24; j++) {
+ KS[i][j] = C[PC2_C[j] - 1];
+ KS[i][j + 24] = D[PC2_D[j] - 29];
+ }
+ }
+
+ for (i = 0; i < 48; i++) {
+ E[i] = e2[i];
+ }
+ }
+
+ // The payoff: encrypt a block.
+ void encrypt(byte[] block, int edflag) {
+ int i, j, ii, t;
+ byte k;
+
+ // First, permute the bits in the input
+ //for (j = 0; j < 64; j++)
+ //{
+ // L[j] = block[IP[j]-1];
+ //}
+ for (j = 0; j < 32; j++)
+ L[j] = block[IP[j] - 1];
+ for (j = 32; j < 64; j++)
+ R[j - 32] = block[IP[j] - 1];
+
+ // Perform an encryption operation 16 times.
+ for (ii = 0; ii < 16; ii++) {
+ i = ii;
+ // Save the R array, which will be the new L.
+ for (j = 0; j < 32; j++)
+ tempL[j] = R[j];
+ // Expand R to 48 bits using the E selector;
+ // exclusive-or with the current key bits.
+ for (j = 0; j < 48; j++)
+ preS[j] = (byte) (R[E[j] - 1] ^ KS[i][j]);
+
+ // The pre-select bits are now considered in 8 groups of
+ // 6 bits each. The 8 selection functions map these 6-bit
+ // quantities into 4-bit quantities and the results permuted
+ // to make an f(R, K). The indexing into the selection functions
+ // is peculiar; it could be simplified by rewriting the tables.
+ for (j = 0; j < 8; j++) {
+ t = 6 * j;
+ k = S[j][ (preS[t ] << 5) +
+ (preS[t + 1] << 3) +
+ (preS[t + 2] << 2) +
+ (preS[t + 3] << 1) +
+ (preS[t + 4]) +
+ (preS[t + 5] << 4) ];
+ t = 4 * j;
+ f[t ] = (byte) ((k >> 3) & 1);
+ f[t + 1] = (byte) ((k >> 2) & 1);
+ f[t + 2] = (byte) ((k >> 1) & 1);
+ f[t + 3] = (byte) ((k) & 1);
+ }
+
+ // The new R is L ^ f(R, K).
+ // The f here has to be permuted first, though.
+ for (j = 0; j < 32; j++) {
+ R[j] = (byte) (L[j] ^ f[P[j] - 1]);
+ }
+
+ // Finally, the new L (the original R) is copied back.
+ for (j = 0; j < 32; j++) {
+ L[j] = tempL[j];
+ }
+ }
+
+ // The output L and R are reversed.
+ for (j = 0; j < 32; j++) {
+ k = L[j];
+ L[j] = R[j];
+ R[j] = k;
+ }
+
+ // The final output gets the inverse permutation of the very original.
+ for (j = 0; j < 64; j++) {
+ //block[j] = L[FP[j]-1];
+ block[j] = (FP[j] > 32) ? R[FP[j] - 33] : L[FP[j] - 1];
+ }
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/DNPattern.java b/pki/base/common/src/com/netscape/cms/authentication/DNPattern.java
new file mode 100644
index 000000000..80d51c4f5
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/DNPattern.java
@@ -0,0 +1,211 @@
+// --- 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.authentication;
+
+
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.publish.*;
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a certificate
+ * subject name from ldap attributes and dn.<p>
+ *
+ * dnpattern is a string representing a subject name pattern to formulate from
+ * the directory attributes and entry dn. If empty or not set, the
+ * ldap entry DN will be used as the certificate subject name. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$attr" "." attrName [ "." attrNumber ] |
+ * name "=" "$dn" "." attrName [ "." attrNumber ] |
+ * "$dn" "." "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US </i>
+ * Ldap entry: dn: UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example2: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * <pre>
+ * Example3: <i>CN=$attr.cn, $rdn.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * followed by the second RDN in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example4: <i>CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN followed by the
+ * first 'ou' value in the user's entry. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * If an attribute or subject DN component does not exist the attribute
+ * is skipped.
+ *
+ * @version $Revision$, $Date$
+ */
+public class DNPattern {
+
+ /* ldap attributes to retrieve */
+ private String[] mLdapAttrs = null;
+
+ /* rdn patterns */
+ protected RDNPattern[] 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 DNPattern(String pattern)
+ throws EAuthException {
+ if (pattern == null || pattern.equals("")) {
+ // create an attribute list that is the dn.
+ mLdapAttrs = new String[] { "dn" };
+ } else {
+ mPatternString = pattern;
+ PushbackReader in = new PushbackReader(new StringReader(pattern));
+
+ parse(in);
+ }
+ }
+
+ public DNPattern(PushbackReader in)
+ throws EAuthException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws EAuthException {
+ Vector rdnPatterns = new Vector();
+ RDNPattern rdnPattern = null;
+ int lastChar = -1;
+
+ do {
+ rdnPattern = new RDNPattern(in);
+ rdnPatterns.addElement(rdnPattern);
+ try {
+ lastChar = in.read();
+ } catch (IOException e) {
+ throw new EAuthException("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString());
+ }
+ }
+ while (lastChar == ',');
+
+ mRDNPatterns = new RDNPattern[rdnPatterns.size()];
+ rdnPatterns.copyInto(mRDNPatterns);
+
+ Vector ldapAttrs = new Vector();
+
+ for (int i = 0; i < mRDNPatterns.length; i++) {
+ String[] rdnAttrs = mRDNPatterns[i].getLdapAttrs();
+
+ if (rdnAttrs != null && rdnAttrs.length > 0)
+ for (int j = 0; j < rdnAttrs.length; j++)
+ ldapAttrs.addElement(rdnAttrs[j]);
+ }
+ mLdapAttrs = new String[ldapAttrs.size()];
+ ldapAttrs.copyInto(mLdapAttrs);
+ }
+
+ /**
+ * Form a Ldap v3 DN string from results of a ldap search.
+ * @param entry LDAPentry from a ldap search
+ * @return Ldap v3 DN string to use for a subject name.
+ */
+ public String formDN(LDAPEntry entry)
+ throws EAuthException {
+ StringBuffer formedDN = new StringBuffer();
+
+ for (int i = 0; i < mRDNPatterns.length; i++) {
+ if (mTestDN != null)
+ mRDNPatterns[i].mTestDN = mTestDN;
+ String rdn = mRDNPatterns[i].formRDN(entry);
+
+ if (rdn != null) {
+ if (rdn != null && rdn.length() != 0) {
+ if (formedDN.length() != 0)
+ formedDN.append(",");
+ formedDN.append(rdn);
+ }
+ }
+ }
+ //System.out.println("formed DN "+formedDN.toString());
+ return formedDN.toString();
+ }
+
+ public String[] getLdapAttrs() {
+ return (String[]) mLdapAttrs.clone();
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/DirBasedAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/DirBasedAuthentication.java
new file mode 100644
index 000000000..1b1394175
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/DirBasedAuthentication.java
@@ -0,0 +1,657 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+
+// cert server imports.
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.cmsutil.util.*;
+
+// cert server x509 imports
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.CertificateSubjectName;
+import netscape.security.x509.CertificateValidity;
+import netscape.security.x509.CertificateExtensions;
+import java.security.cert.CertificateException;
+
+// java sdk imports.
+import java.util.Locale;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Date;
+import java.io.IOException;
+
+
+/**
+ * Abstract class for directory based authentication managers
+ * Uses a pattern for formulating subject names.
+ * The pattern is read from configuration file.
+ * Syntax of the pattern is described in the init() method.
+ *
+ * <P>
+ * @version $Revision$, $Date$
+ */
+public abstract class DirBasedAuthentication
+ implements IAuthManager, IExtendedPluginInfo {
+
+ protected static final String USER_DN = "userDN";
+
+ /* configuration parameter keys */
+ protected static final String PROP_LDAP = "ldap";
+ protected static final String PROP_BASEDN = "basedn";
+ protected static final String PROP_DNPATTERN = "dnpattern";
+ protected static final String PROP_LDAPSTRINGATTRS = "ldapStringAttributes";
+ protected static final String PROP_LDAPBYTEATTRS = "ldapByteAttributes";
+
+ // members
+
+ /* name of this authentication manager instance */
+ protected String mName = null;
+
+ /* name of the authentication manager plugin */
+ protected String mImplName = null;
+
+ /* configuration store */
+ protected IConfigStore mConfig;
+
+ /* ldap configuration sub-store */
+ protected IConfigStore mLdapConfig;
+
+ /* ldap base dn */
+ protected String mBaseDN = null;
+
+ /* factory of anonymous ldap connections */
+ protected ILdapConnFactory mConnFactory = null;
+
+ /* the system logger */
+ protected ILogger mLogger = CMS.getLogger();
+
+ /* the subject DN pattern */
+ protected DNPattern mPattern = null;
+
+ /* the list of LDAP attributes with string values to retrieve to
+ * save in the auth token including ones from the dn pattern. */
+ protected String[] mLdapStringAttrs = null;
+
+ /* the list of LDAP attributes with byte[] values to retrive to save
+ * in authtoken. */
+ protected String[] mLdapByteAttrs = null;
+
+ /* the combined list of LDAP attriubutes to retrieve*/
+ protected String[] mLdapAttrs = null;
+
+ /* default dn pattern if left blank or not set in the config */
+ protected static String DEFAULT_DNPATTERN =
+ "E=$attr.mail, CN=$attr.cn, O=$dn.o, C=$dn.c";
+
+ /* Vector of extendedPluginInfo strings */
+ protected static Vector mExtendedPluginInfo = null;
+
+ static {
+ mExtendedPluginInfo = new Vector();
+ mExtendedPluginInfo.add(PROP_DNPATTERN + ";string;Template for cert" +
+ " Subject Name. ($dn.xxx - get value from user's LDAP " +
+ "DN. $attr.yyy - get value from LDAP attributes in " +
+ "user's entry.) Default: " + DEFAULT_DNPATTERN);
+ mExtendedPluginInfo.add(PROP_LDAPSTRINGATTRS + ";string;" +
+ "Comma-separated list of LDAP attributes to copy from " +
+ "the user's LDAP entry into the AuthToken. e.g use " +
+ "'mail' to copy user's email address for subjectAltName");
+ mExtendedPluginInfo.add(PROP_LDAPBYTEATTRS + ";string;" +
+ "Comma-separated list of binary LDAP attributes to copy" +
+ " from the user's LDAP entry into the AuthToken");
+ mExtendedPluginInfo.add("ldap.ldapconn.host;string,required;" +
+ "LDAP host to connect to");
+ mExtendedPluginInfo.add("ldap.ldapconn.port;number,required;" +
+ "LDAP port number (use 389, or 636 if SSL)");
+ mExtendedPluginInfo.add("ldap.ldapconn.secureConn;boolean;" +
+ "Use SSL to connect to directory?");
+ mExtendedPluginInfo.add("ldap.ldapconn.version;choice(3,2);" +
+ "LDAP protocol version");
+ mExtendedPluginInfo.add("ldap.basedn;string,required;Base DN to start searching " +
+ "under. If your user's DN is 'uid=jsmith, o=company', you " +
+ "might want to use 'o=company' here");
+ mExtendedPluginInfo.add("ldap.minConns;number;number of connections " +
+ "to keep open to directory server. Default 5.");
+ mExtendedPluginInfo.add("ldap.maxConns;number;when needed, connection " +
+ "pool can grow to this many (multiplexed) connections. Default 1000.");
+ }
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public DirBasedAuthentication() {
+ }
+
+ /**
+ * Initializes the UidPwdDirBasedAuthentication auth manager.
+ *
+ * Takes the following configuration parameters: <br>
+ * <pre>
+ * ldap.basedn - the ldap base dn.
+ * ldap.ldapconn.host - the ldap host.
+ * ldap.ldapconn.port - the ldap port
+ * ldap.ldapconn.secureConn - whether port should be secure
+ * ldap.minConns - minimum connections
+ * ldap.maxConns - max connections
+ * dnpattern - dn pattern.
+ * </pre>
+ * <p>
+ * <i><b>dnpattern</b></i> is a string representing a subject name pattern
+ * to formulate from the directory attributes and entry dn. If empty or
+ * not set, the ldap entry DN will be used as the certificate subject name.
+ * <p>
+ * The syntax is
+ * <pre>
+ * dnpattern = SubjectNameComp *[ "," SubjectNameComp ]
+ *
+ * SubjectNameComponent = DnComp | EntryComp | ConstantComp
+ * DnComp = CertAttr "=" "$dn" "." DnAttr "." Num
+ * EntryComp = CertAttr "=" "$attr" "." EntryAttr "." Num
+ * ConstantComp = CertAttr "=" Constant
+ * DnAttr = an attribute in the Ldap entry dn
+ * EntryAttr = an attribute in the Ldap entry
+ * CertAttr = a Component in the Certificate Subject Name
+ * (multiple AVA in one RDN not supported)
+ * Num = the nth value of tha attribute in the dn or entry.
+ * Constant = Constant String, with any accepted ldap string value.
+ *
+ * </pre>
+ * <p>
+ * <b>Example:</b>
+ * <pre>
+ * dnpattern:
+ * E=$attr.mail.1, CN=$attr.cn, OU=$attr.ou.2, O=$dn.o, C=US
+ * <br>
+ * Ldap entry dn:
+ * UID=joesmith, OU=people, O=Acme.com
+ * <br>
+ * Ldap attributes:
+ * cn: Joe Smith
+ * sn: Smith
+ * mail: joesmith@acme.com
+ * mail: joesmith@redhat.com
+ * ou: people
+ * ou: IS
+ * <i>etc.</i>
+ * </pre>
+ * <p>
+ * The subject name formulated in the cert will be : <br>
+ * <pre>
+ * E=joesmith@acme.com, CN=Joe Smith, OU=Human Resources, O=Acme.com, C=US
+ *
+ * E = the first 'mail' ldap attribute value in user's entry - joesmithe@acme.com
+ * CN = the (first) 'cn' ldap attribute value in the user's entry - Joe Smith
+ * OU = the second 'ou' value in the ldap entry - IS
+ * O = the (first) 'o' value in the user's entry DN - "Acme.com"
+ * C = the constant string "US"
+ * </pre>
+ *
+ * @param name The name for this authentication manager instance.
+ * @param implName The name of the authentication manager plugin.
+ * @param config - The configuration store for this instance.
+ * @exception EBaseException If an error occurs during initialization.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ init(name, implName, config, true);
+ }
+
+ public void init(String name, String implName, IConfigStore config, boolean needBaseDN)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+
+ /* initialize ldap server configuration */
+ mLdapConfig = mConfig.getSubStore(PROP_LDAP);
+ if (needBaseDN) mBaseDN = mLdapConfig.getString(PROP_BASEDN);
+ if (needBaseDN && ((mBaseDN == null) || (mBaseDN.length() == 0) || (mBaseDN.trim().equals(""))))
+ throw new EPropertyNotFound(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", "basedn"));
+ mConnFactory = CMS.getLdapAnonConnFactory();
+ mConnFactory.init(mLdapConfig);
+
+ /* initialize dn pattern */
+ String pattern = mConfig.getString(PROP_DNPATTERN, null);
+
+ if (pattern == null || pattern.length() == 0)
+ pattern = DEFAULT_DNPATTERN;
+ mPattern = new DNPattern(pattern);
+ String[] patternLdapAttrs = mPattern.getLdapAttrs();
+
+ /* initialize ldap string attribute list */
+ String ldapStringAttrs = mConfig.getString(PROP_LDAPSTRINGATTRS, null);
+
+ if (ldapStringAttrs == null) {
+ mLdapStringAttrs = patternLdapAttrs;
+ } else {
+ StringTokenizer pAttrs =
+ new StringTokenizer(ldapStringAttrs, ",", false);
+ int begin = 0;
+
+ if (patternLdapAttrs != null && patternLdapAttrs.length > 0) {
+ mLdapStringAttrs = new String[
+ patternLdapAttrs.length + pAttrs.countTokens()];
+ System.arraycopy(patternLdapAttrs, 0,
+ mLdapStringAttrs, 0, patternLdapAttrs.length);
+ begin = patternLdapAttrs.length;
+ } else {
+ mLdapStringAttrs = new String[pAttrs.countTokens()];
+ }
+ for (int i = begin; i < mLdapStringAttrs.length; i++) {
+ mLdapStringAttrs[i] = ((String) pAttrs.nextElement()).trim();
+ }
+ }
+
+ /* initialize ldap byte[] attribute list */
+ String ldapByteAttrs = mConfig.getString(PROP_LDAPBYTEATTRS, null);
+
+ if (ldapByteAttrs == null) {
+ mLdapByteAttrs = new String[0];
+ } else {
+ StringTokenizer byteAttrs =
+ new StringTokenizer(ldapByteAttrs, ",", false);
+
+ mLdapByteAttrs = new String[byteAttrs.countTokens()];
+ for (int j = 0; j < mLdapByteAttrs.length; j++) {
+ mLdapByteAttrs[j] = ((String) byteAttrs.nextElement()).trim();
+ }
+ }
+
+ /* make the combined list */
+ mLdapAttrs =
+ new String[mLdapStringAttrs.length + mLdapByteAttrs.length];
+ System.arraycopy(mLdapStringAttrs, 0, mLdapAttrs,
+ 0, mLdapStringAttrs.length);
+ System.arraycopy(mLdapByteAttrs, 0, mLdapAttrs,
+ mLdapStringAttrs.length, mLdapByteAttrs.length);
+
+ log(ILogger.LL_INFO, CMS.getLogMessage("CMS_AUTH_INIT_DONE"));
+ }
+
+ /**
+ * gets the name of this authentication manager instance
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * gets the plugin name of this authentication manager.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ /**
+ * Authenticates user through LDAP by a set of credentials.
+ * Resulting AuthToken a TOKEN_CERTINFO field of a X509CertInfo
+ * <p>
+ * @param authCred Authentication credentials, CRED_UID and CRED_PWD.
+ * @return A AuthToken with a TOKEN_SUBJECT of X500name type.
+ * @exception com.netscape.certsrv.authentication.EMissingCredential
+ * If a required authentication credential is missing.
+ * @exception com.netscape.certsrv.authentication.EInvalidCredentials
+ * If credentials failed authentication.
+ * @exception com.netscape.certsrv.base.EBaseException
+ * If an internal error occurred.
+ * @see com.netscape.certsrv.authentication.AuthToken
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+ String userdn = null;
+ LDAPConnection conn = null;
+ AuthToken authToken = new AuthToken(this);
+
+ try {
+ if (mConnFactory == null) {
+ conn = null;
+ } else {
+ conn = mConnFactory.getConn();
+ }
+
+ // authenticate the user and get a user entry.
+ userdn = authenticate(conn, authCred, authToken);
+ authToken.set(USER_DN, userdn);
+
+ // formulate the cert info.
+ // set each seperatly since otherwise they won't serialize
+ // in the request queue.
+ X509CertInfo certInfo = new X509CertInfo();
+
+ formCertInfo(conn, userdn, certInfo, authToken);
+
+ // set subject name.
+ try {
+ CertificateSubjectName subjectname = (CertificateSubjectName)
+ certInfo.get(X509CertInfo.SUBJECT);
+
+ if (subjectname != null)
+ authToken.set(AuthToken.TOKEN_CERT_SUBJECT,
+ subjectname.toString());
+ } // error means it's not set.
+ catch (CertificateException e) {
+ } catch (IOException e) {
+ }
+
+ // set validity if any
+ try {
+ CertificateValidity validity = (CertificateValidity)
+ certInfo.get(X509CertInfo.VALIDITY);
+
+ if (validity != null) {
+ // the gets throws IOException but only if attribute
+ // not recognized. In these cases they are always.
+ authToken.set(AuthToken.TOKEN_CERT_NOTBEFORE,
+ (Date)validity.get(CertificateValidity.NOT_BEFORE));
+ authToken.set(AuthToken.TOKEN_CERT_NOTAFTER,
+ (Date)validity.get(CertificateValidity.NOT_AFTER));
+ }
+ } // error means it's not set.
+ catch (CertificateException e) {
+ } catch (IOException e) {
+ }
+
+ // set extensions if any.
+ try {
+ CertificateExtensions extensions = (CertificateExtensions)
+ certInfo.get(X509CertInfo.EXTENSIONS);
+
+ if (extensions != null)
+ authToken.set(AuthToken.TOKEN_CERT_EXTENSIONS, extensions);
+ } // error means it's not set.
+ catch (CertificateException e) {
+ } catch (IOException e) {
+ }
+
+ } finally {
+ if (conn != null)
+ mConnFactory.returnConn(conn);
+ }
+
+ return authToken;
+ }
+
+ /**
+ * get the list of required credentials.
+ * @return list of required credentials as strings.
+ */
+ public abstract String[] getRequiredCreds();
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public abstract String[] getConfigParams();
+
+ /**
+ * disconnects the ldap connections
+ */
+ public void shutdown() {
+ try {
+ if (mConnFactory != null) {
+ mConnFactory.reset();
+ mConnFactory = null;
+ }
+ } catch (ELdapException e) {
+ // ignore
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_SHUTDOWN_ERROR", e.toString()));
+ }
+ }
+
+ /**
+ * Gets the configuration substore used by this authentication manager
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * Authenticates a user through directory based a set of credentials.
+ *
+ * @param authCreds The authentication credentials.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the uid and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected abstract String authenticate(
+ LDAPConnection conn, IAuthCredentials authCreds, AuthToken token)
+ throws EBaseException;
+
+ /**
+ * Formulate the cert info.
+ *
+ * @param conn A LDAP Connection authenticated to user to use.
+ * @param userdn The user's dn.
+ * @param certinfo A certinfo object to fill.
+ * @param token A authentication token to fill.
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected void formCertInfo(LDAPConnection conn,
+ String userdn,
+ X509CertInfo certinfo,
+ AuthToken token)
+ throws EBaseException {
+ String dn = null;
+ // get ldap attributes to retrieve.
+ String[] attrs = getLdapAttrs();
+
+ // retrieve the attributes.
+ try {
+ if (conn != null) {
+ LDAPEntry entry = null;
+ LDAPSearchResults results =
+ conn.search(userdn, LDAPv2.SCOPE_BASE, "objectclass=*",
+ attrs, false);
+
+ if (!results.hasMoreElements()) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_ATTR_ERROR"));
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_LDAPATTRIBUTES_NOT_FOUND"));
+ }
+ entry = results.next();
+
+ // formulate the subject dn
+ try {
+ dn = formSubjectName(entry);
+ } catch (EBaseException e) {
+ //e.printStackTrace();
+ throw e;
+ }
+ // Put selected values from the entry into the token
+ setAuthTokenValues(entry, token);
+ } else {
+ dn = userdn;
+ }
+
+ // add anything else in cert info such as validity, extensions
+ // (nothing now)
+
+ // pack the dn into X500name and set subject name.
+ if (dn.length() == 0) {
+ EBaseException ex =
+ new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_EMPTY_DN_FORMED", mName));
+
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_DN_ERROR", ex.toString()));
+ throw ex;
+ }
+ X500Name subjectdn = new X500Name(dn);
+
+ certinfo.set(X509CertInfo.SUBJECT,
+ new CertificateSubjectName(subjectdn));
+ } catch (LDAPException e) {
+ switch (e.getLDAPResultCode()) {
+ case LDAPException.SERVER_DOWN:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_AUTH_ATTR_ERROR"));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+
+ case LDAPException.NO_SUCH_OBJECT:
+ case LDAPException.LDAP_PARTIAL_RESULTS:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_NO_USER_ENTRY_ERROR", userdn));
+
+ // fall to below.
+ default:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.toString()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_OTHER_LDAP_EXCEPTION",
+ e.errorCodeToString()));
+ }
+ } catch (IOException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_CREATE_SUBJECT_ERROR", userdn, e.getMessage()));
+ throw new EFormSubjectDN(CMS.getUserMessage("CMS_AUTHENTICATION_FORM_SUBJECTDN_ERROR"));
+ } catch (CertificateException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_CREATE_CERTINFO_ERROR", userdn, e.getMessage()));
+ throw new EFormSubjectDN(CMS.getUserMessage("CMS_AUTHENTICATION_FORM_SUBJECTDN_ERROR"));
+ }
+ }
+
+ /**
+ * Copy values from the LDAPEntry into the AuthToken. The
+ * list of values that should be store this way is given in
+ * a the ldapAttributes configuration parameter.
+ */
+ protected void setAuthTokenValues(LDAPEntry e, AuthToken tok) {
+ for (int i = 0; i < mLdapStringAttrs.length; i++)
+ setAuthTokenStringValue(mLdapStringAttrs[i], e, tok);
+ for (int j = 0; j < mLdapByteAttrs.length; j++)
+ setAuthTokenByteValue(mLdapByteAttrs[j], e, tok);
+ }
+
+ protected void setAuthTokenStringValue(
+ String name, LDAPEntry entry, AuthToken tok) {
+ LDAPAttribute values = entry.getAttribute(name);
+
+ if (values == null) return;
+
+ Vector v = new Vector();
+ Enumeration e = values.getStringValues();
+
+ while (e.hasMoreElements()) {
+ v.addElement(e.nextElement());
+ }
+
+ String a[] = new String[v.size()];
+
+ v.copyInto(a);
+
+ tok.set(name, a);
+ }
+
+ protected void setAuthTokenByteValue(
+ String name, LDAPEntry entry, AuthToken tok) {
+ LDAPAttribute values = entry.getAttribute(name);
+
+ if (values == null) return;
+
+ Vector v = new Vector();
+ Enumeration e = values.getByteValues();
+
+ while (e.hasMoreElements()) {
+ v.addElement(e.nextElement());
+ }
+
+ byte[][] a = new byte[v.size()][];
+
+ v.copyInto(a);
+
+ tok.set(name, a);
+ }
+
+ /**
+ * Return a list of LDAP attributes with String values to retrieve.
+ * Subclasses can override to return any set of attributes.
+ * @return Array of LDAP attributes to retrieve from the directory.
+ */
+ protected String[] getLdapAttrs() {
+ return mLdapAttrs;
+ }
+
+ /**
+ * Return a list of LDAP attributes with byte[] values to retrieve.
+ * Subclasses can override to return any set of attributes.
+ * @return Array of LDAP attributes to retrieve from the directory.
+ */
+ protected String[] getLdapByteAttrs() {
+ return mLdapByteAttrs;
+ }
+
+ /**
+ * Formulate the subject name
+ * @param entry The LDAP entry
+ * @return The subject name string.
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected String formSubjectName(LDAPEntry entry)
+ throws EAuthException {
+ if (mPattern.mPatternString == null)
+ return entry.getDN();
+
+ /*
+ if (mTestDNString != null) {
+ mPattern.mTestDN = mTestDNString;
+ //System.out.println("Set DNPattern.mTestDN to "+mPattern.mTestDN);
+ }
+ */
+
+ String dn = mPattern.formDN(entry);
+
+ CMS.debug("DirBasedAuthentication: formed DN '" + dn + "'");
+ return dn;
+ }
+
+ /**
+ * Logs a message for this class in the system log file.
+ * @param level The log level.
+ * @param msg The message to log.
+ * @see com.netscape.certsrv.logging.ILogger
+ */
+ protected void log(int level, String msg) {
+ if (mLogger == null)
+ return;
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_AUTHENTICATION,
+ level, msg);
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] s = Utils.getStringArrayFromVector(mExtendedPluginInfo);
+
+ return s;
+
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/FlatFileAuth.java b/pki/base/common/src/com/netscape/cms/authentication/FlatFileAuth.java
new file mode 100644
index 000000000..a03b298e6
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/FlatFileAuth.java
@@ -0,0 +1,678 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.StringTokenizer;
+import java.util.Date;
+import java.text.SimpleDateFormat;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.authentication.AuthToken;
+import com.netscape.certsrv.authentication.EInvalidCredentials;
+import com.netscape.certsrv.authentication.EMissingCredential;
+import com.netscape.certsrv.authentication.IAuthCredentials;
+import com.netscape.certsrv.authentication.IAuthManager;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.logging.ILogger;
+
+
+/**
+ * This represents the authentication manager that authenticates
+ * user against a file where id, and password are stored.
+ *
+ * @version $Revision$, $Date$
+ */
+public class FlatFileAuth
+ implements IProfileAuthenticator, IExtendedPluginInfo {
+
+ /* configuration parameter keys */
+ protected static final String PROP_FILENAME = "fileName";
+ protected static final String PROP_KEYATTRIBUTES = "keyAttributes";
+ protected static final String PROP_AUTHATTRS = "authAttributes";
+ protected static final String PROP_DEFERONFAILURE = "deferOnFailure";
+
+ protected String mFilename = "config/pwfile";
+ protected long mFileLastRead = 0;
+ protected String mKeyAttributes = "UID";
+ protected String mAuthAttrs = "PWD";
+ protected boolean mDeferOnFailure = true;
+ private static final String DATE_PATTERN = "yyyy-MM-dd-HH-mm-ss";
+ private static SimpleDateFormat mDateFormat = new SimpleDateFormat(DATE_PATTERN);
+
+ protected static String[] mConfigParams =
+ new String[] {
+ PROP_FILENAME,
+ PROP_KEYATTRIBUTES,
+ PROP_AUTHATTRS,
+ PROP_DEFERONFAILURE
+ };
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String s[] = {
+ PROP_FILENAME + ";string;Pathname of password file",
+ PROP_KEYATTRIBUTES + ";string;Comma-separated list of attributes" +
+ " which together form a unique identifier for the user",
+ PROP_AUTHATTRS + ";string;Comma-separated list of attributes" +
+ " which are used for further authentication",
+ PROP_DEFERONFAILURE + ";boolean;if user is not found, defer the " +
+ "request to the queue for manual-authentication (true), or " +
+ "simply rejected the request (false)"
+ };
+
+ return s;
+ }
+
+ /** name of this authentication manager instance */
+ protected String mName = null;
+
+ protected String FFAUTH = "FlatFileAuth";
+
+ /** name of the authentication manager plugin */
+ protected String mImplName = null;
+
+ /** configuration store */
+ protected IConfigStore mConfig = null;
+
+ /** system logger */
+ protected ILogger mLogger = CMS.getLogger();
+
+ /** This array is created as to include all the requested attributes
+ *
+ */
+ String[] reqCreds = null;
+
+ String[] authAttrs = null;
+ String[] keyAttrs = null;
+
+ /** Hashtable of entries from Auth File. Hash index is the
+ * concatenation of the attributes from matchAttributes property
+ */
+ protected Hashtable entries = null;
+
+ /**
+ * Get the named property
+ * If the property is not set, use s as the default, and create
+ * a new value for the property in the config file.
+ *
+ * @param propertyName Property name
+ * @param s The default value of the property
+ */
+ protected String getPropertyS(String propertyName, String s)
+ throws EBaseException {
+ String p;
+
+ try {
+ p = mConfig.getString(propertyName);
+ } catch (EPropertyNotFound e) {
+ mConfig.put(propertyName, s);
+ p = s;
+ }
+ return p;
+ }
+
+ public boolean isSSLClientRequired() {
+ return false;
+ }
+
+ /**
+ * Get the named property,
+ * If the property is not set, use b as the default, and create
+ * a new value for the property in the config file.
+ *
+ * @param propertyName Property name
+ * @param b The default value of the property
+ */
+ protected boolean getPropertyB(String propertyName, boolean b)
+ throws EBaseException {
+ boolean p;
+
+ try {
+ p = mConfig.getBoolean(propertyName);
+ } catch (EPropertyNotFound e) {
+ mConfig.put(propertyName, b ? "true" : "false");
+ p = b;
+ }
+ return p;
+ }
+
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+
+ try {
+ mFilename = getPropertyS(PROP_FILENAME, mFilename);
+ mKeyAttributes = getPropertyS(PROP_KEYATTRIBUTES, mKeyAttributes);
+ mAuthAttrs = getPropertyS(PROP_AUTHATTRS, mAuthAttrs);
+ mDeferOnFailure = getPropertyB(PROP_DEFERONFAILURE, mDeferOnFailure);
+ } catch (EBaseException e) {
+ return;
+ }
+
+ keyAttrs = splitOnComma(mKeyAttributes);
+ authAttrs = splitOnComma(mAuthAttrs);
+
+ String[][] stringArrays = new String[2][];
+
+ stringArrays[0] = keyAttrs;
+ stringArrays[1] = authAttrs;
+ reqCreds = unionOfStrings(stringArrays);
+
+ print("mFilename = " + mFilename);
+ print("mKeyAttributes = " + mKeyAttributes);
+ print("mAuthAttrs = " + mAuthAttrs);
+ for (int i = 0; i < stringArrays.length; i++) {
+ for (int j = 0; j < stringArrays[i].length; j++) {
+ print("stringArrays[" + i + "][" + j + "] = " + stringArrays[i][j]);
+ }
+ }
+
+ try {
+ File file = new File(mFilename);
+
+ mFileLastRead = file.lastModified();
+ entries = readFile(file, keyAttrs);
+ CMS.debug("FlatFileAuth: " + CMS.getLogMessage("CMS_AUTH_READ_ENTRIES", mFilename));
+ // printAllEntries();
+ } catch (IOException e) {
+ throw new EBaseException(mName + " authentication: Could not open file " + mFilename + " (" + e.getMessage() + ")");
+ } catch (java.lang.StringIndexOutOfBoundsException ee) {
+ CMS.debug("FlatFileAuth: " + CMS.getLogMessage("OPERATION_ERROR", ee.toString()));
+ }
+
+ }
+
+ /**
+ * Log a message.
+ * @param level The logging level.
+ * @param msg The message to log.
+ */
+ private void log(int level, String msg) {
+ if (mLogger == null)
+ return;
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_AUTHENTICATION,
+ level, msg);
+ }
+
+ void print(String s) {
+ CMS.debug("FlatFileAuth: " + s);
+ }
+
+ /**
+ * Return a string array which is the union of all the string arrays
+ * passed in. The strings are treated as case sensitive
+ */
+
+ public String[] unionOfStrings(String[][] stringArrays) {
+ Hashtable ht = new Hashtable();
+
+ for (int i = 0; i < stringArrays.length; i++) {
+ String[] sa = stringArrays[i];
+
+ for (int j = 0; j < sa.length; j++) {
+ print("unionOfStrings: " + i + "," + j + " = " + sa[j]);
+ ht.put(sa[j], "");
+ }
+ }
+
+ String[] s = new String[ht.size()];
+ Enumeration e = ht.keys();
+
+ for (int i = 0; e.hasMoreElements(); i++) {
+ s[i] = (String) e.nextElement();
+ }
+ return s;
+
+ }
+
+ /**
+ * Split a comma-delimited String into an array of individual
+ * Strings.
+ */
+ private String[] splitOnComma(String s) {
+ print("Splitting String: " + s + " on commas");
+ StringTokenizer st = new StringTokenizer(s, ",", false);
+ String[] sa = new String[st.countTokens()];
+
+ print(" countTokens:" + st.countTokens());
+
+ for (int i = 0; i < sa.length; i++) {
+ String p = st.nextToken().trim();
+
+ print(" token " + i + " = " + p);
+ sa[i] = p;
+ }
+
+ return sa;
+ }
+
+ /**
+ * Join an array of Strings into one string, with
+ * the specified string between each string
+ */
+
+ private String joinStringArray(String[] s, String sep) {
+
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < s.length; i++) {
+ sb.append(s[i]);
+ if (i < (s.length - 1)) {
+ sb.append(sep);
+ }
+ }
+ return sb.toString();
+ }
+
+ private synchronized void updateFile (String key) {
+ try {
+ String name = writeFile (key);
+ if (name != null) {
+ File orgFile = new File(mFilename);
+ long lastModified = orgFile.lastModified();
+ File newFile = new File(name);
+ if (lastModified > mFileLastRead) {
+ mFileLastRead = lastModified;
+ } else {
+ mFileLastRead = newFile.lastModified();
+ }
+ if (orgFile.renameTo(new File(name.substring(0, name.length()-1)))) {
+ if (!newFile.renameTo(new File(mFilename))) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("RENAME_FILE_ERROR", name, mFilename));
+ File file = new File(name.substring(0, name.length()-1));
+ file.renameTo(new File(mFilename));
+ }
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("RENAME_FILE_ERROR", mFilename,
+ name.substring(0, name.length()-1)));
+ }
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("FILE_ERROR", e.getMessage()));
+ }
+ }
+
+ private String writeFile (String key) {
+ BufferedReader reader = null;
+ BufferedWriter writer = null;
+ String name = null;
+ boolean commentOutNextLine = false;
+ boolean done = false;
+ String line = null;
+ try {
+ reader = new BufferedReader (new FileReader (mFilename));
+ name = mFilename+"."+mDateFormat.format(new Date())+"~";
+ writer = new BufferedWriter (new FileWriter(name));
+ if (reader != null && writer != null) {
+ while ((line = reader.readLine()) != null) {
+ if (commentOutNextLine) {
+ writer.write("#");
+ commentOutNextLine = false;
+ }
+ if (line.indexOf(key) > -1) {
+ writer.write("#");
+ commentOutNextLine = true;
+ }
+ writer.write(line);
+ writer.newLine();
+ }
+ done = true;
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("FILE_ERROR", e.getMessage()));
+ }
+
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ if (writer != null) {
+ writer.flush();
+ writer.close();
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("FILE_ERROR", e.getMessage()));
+ }
+
+ try {
+ if (!done) {
+ long s1 = 0;
+ long s2 = 0;
+ File f1 = new File(mFilename);
+ File f2 = new File(name);
+ if (f1.exists()) s1 = f1.length();
+ if (f2.exists()) s2 = f2.length();
+ if (s1 > 0 && s2 > 0 && s2 > s1) {
+ done = true;
+ } else {
+ if (f2.exists()) f2.delete();
+ name = null;
+ }
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("FILE_ERROR", e.getMessage()));
+ }
+
+ return name;
+ }
+
+
+ /**
+ * Read a file with the following format: <p><pre>
+ * param1: valuea
+ * param2: valueb
+ * -blank-line-
+ * param1: valuec
+ * param2: valued
+ * </pre>
+ *
+ * @param f The file to read
+ * @param keys The parameters to concat together to form the hash
+ * key
+ * @return a hashtable of hashtables.
+ */
+ protected Hashtable readFile(File f, String[] keys)
+ throws IOException {
+ log(ILogger.LL_INFO, "Reading file: " + f.getName());
+ BufferedReader file = new BufferedReader(
+ new FileReader(f)
+ );
+
+ String line;
+ Hashtable allusers = new Hashtable();
+ Hashtable entry = null;
+ int linenum = 0;
+
+ while ((line = file.readLine()) != null) {
+ linenum++;
+ line = line.trim();
+ if (line.length() > 0 && line.charAt(0) == '#') {
+ continue;
+ }
+ int colon = line.indexOf(':');
+
+ if (entry == null) {
+ entry = new Hashtable();
+ }
+
+ if (colon == -1) { // no colon -> empty line signifies end of record
+ if (!line.trim().equals("")) {
+ if (file != null) {
+ file.close();
+ }
+ throw new IOException(FFAUTH + ": Parsing error, " +
+ "colon missing from line " + linenum + " of " + f.getName());
+ }
+ if (entry.size() > 0) {
+ putEntry(allusers, entry, keys);
+ entry = null;
+ }
+ continue;
+ }
+
+ String attr = line.substring(0, colon).trim();
+ String val = line.substring(colon + 1).trim();
+
+ entry.put(attr, val);
+ }
+
+ putEntry(allusers, entry, keys);
+ if (file != null) {
+ file.close();
+ }
+ return allusers;
+ }
+
+ private void putEntry(Hashtable allUsers,
+ Hashtable entry,
+ String[] keys) {
+ if (entry == null) {
+ return;
+ }
+ String key = "";
+
+ print("keys.length = " + keys.length);
+ for (int i = 0; i < keys.length; i++) {
+ String s = (String) entry.get(keys[i]);
+
+ print(" concatenating: " + s);
+ if (s != null) {
+ key = key.concat(s);
+ }
+ }
+ print("putting: key " + key);
+ allUsers.put(key, entry);
+ }
+
+ void printAllEntries() {
+ Enumeration e = entries.keys();
+
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+
+ print("* " + key + " *");
+ Hashtable ht = (Hashtable) entries.get(key);
+ Enumeration f = ht.keys();
+
+ while (f.hasMoreElements()) {
+ String fkey = (String) f.nextElement();
+
+ print(" " + fkey + " -> " + ht.get(fkey));
+ }
+ }
+ }
+
+ /**
+ * Compare attributes provided by the user with those in
+ * in flat file.
+ *
+ */
+
+ private IAuthToken doAuthentication(Hashtable user, IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+ AuthToken authToken = new AuthToken(this);
+
+ for (int i = 0; i < authAttrs.length; i++) {
+ String ffvalue = (String) user.get(authAttrs[i]);
+ String uservalue = (String) authCred.get(authAttrs[i]);
+
+ // print("checking authentication token (" + authAttrs[i] + ": " + uservalue + " against ff value: " + ffvalue);
+ if (!ffvalue.equals(uservalue)) {
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ }
+ return authToken;
+ }
+
+ private void reReadPwFile() {
+
+ try {
+ File file = new File(mFilename);
+ long pwfilelastmodified = file.lastModified();
+
+ if (pwfilelastmodified > mFileLastRead) {
+ mFileLastRead = pwfilelastmodified;
+ entries = readFile(file, keyAttrs);
+ // printAllEntries();
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("READ_FILE_ERROR", mFilename, e.getMessage()));
+ }
+ }
+
+ /**
+ * Authenticate the request
+ *
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+ IAuthToken authToken = null;
+ String keyForUser = "";
+
+ /* First check if hashtable has been modified since we last read it in */
+
+ reReadPwFile();
+
+ /* Find the user in our hashtable */
+
+ for (int i = 0; i < keyAttrs.length; i++) {
+ print("concatenating string i=" + i + " keyAttrs[" + i + "] = " + keyAttrs[i]);
+ String credential = (String) authCred.get(keyAttrs[i]);
+
+ if (credential == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", keyAttrs[i]));
+ }
+ keyForUser = keyForUser.concat((String) authCred.get(keyAttrs[i]));
+ }
+ print("authenticating user: finding user from key: " + keyForUser);
+
+ Hashtable user = (Hashtable) entries.get(keyForUser);
+
+ try {
+ if (user != null) {
+ authToken = doAuthentication(user, authCred);
+ } else {
+ CMS.debug("FlatFileAuth: " + CMS.getLogMessage("CMS_AUTH_USER_NOT_FOUND"));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ } catch (EInvalidCredentials e) {
+ // If defer on failure is false, then we re-throw the exception
+ // which causes the request to be rejected
+ if (!mDeferOnFailure) {
+ throw e;
+ } else {
+ CMS.debug("FlatFileAuth: Since defering on failure - ignore invalid creds");
+ }
+ }
+
+ // if a dn was specified in the password file for this user,
+ // replace the requested dn with the one in the pwfile
+ if (user != null) {
+ String dn = (String) user.get("dn");
+
+ if (dn != null && authToken != null) {
+ authToken.set(AuthToken.TOKEN_CERT_SUBJECT, dn);
+ }
+ }
+
+ // If defer on failure is true, and the auth failed, authToken will
+ // be null here, which causes the request to be deferred.
+
+ if (user != null && authToken != null) {
+ entries.remove(keyForUser);
+ updateFile(keyForUser);
+ // printAllEntries();
+ }
+ return authToken;
+ }
+
+ /**
+ * Return a list of HTTP parameters which will be taken from the
+ * request posting and placed into the AuthCredentials block
+ *
+ * Note that this method will not be called until after the
+ * init() method is called
+ */
+ public String[] getRequiredCreds() {
+ print("getRequiredCreds returning: " + joinStringArray(reqCreds, ","));
+ return reqCreds;
+
+ }
+
+ /**
+ * Returns a list of configuration parameters, so the console
+ * can prompt the user when configuring.
+ */
+ public String[] getConfigParams() {
+ return mConfigParams;
+ }
+
+ /**
+ * Returns the configuration store used by this authentication manager
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ public void shutdown() {
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public String getImplName() {
+ return mImplName;
+ }
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_NAME");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ return null;
+ }
+
+ public boolean isValueWriteable(String name) {
+ return false;
+ }
+
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_TEXT");
+ }
+
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/HashAuthData.java b/pki/base/common/src/com/netscape/cms/authentication/HashAuthData.java
new file mode 100644
index 000000000..fe05dec9d
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/HashAuthData.java
@@ -0,0 +1,117 @@
+// --- 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.authentication;
+
+
+// java sdk imports.
+import java.util.Hashtable;
+import java.util.Vector;
+import java.io.IOException;
+
+
+/**
+ * The structure stores the information of which machine is enabled for
+ * the agent-initiated user enrollment, and whom agents enable this feature,
+ * and the value of the timeout.
+ * <P>
+ * @version $Revision$, $Date$
+ */
+public class HashAuthData extends Hashtable {
+
+ public static final long TIMEOUT = 600000;
+ public static final long LASTLOGIN = 0;
+
+ public HashAuthData() {
+ }
+
+ public String getAgentName(String hostname) {
+ Vector val = (Vector) get(hostname);
+
+ if (val != null)
+ return (String) val.elementAt(0);
+ return null;
+ }
+
+ public void setAgentName(String hostname, String agentName) {
+ Vector val = (Vector) get(hostname);
+
+ if (val == null) {
+ val = new Vector();
+ put(hostname, val);
+ }
+ val.setElementAt(agentName, 0);
+ }
+
+ public long getTimeout(String hostname) {
+ Vector val = (Vector) get(hostname);
+
+ if (val != null) {
+ return ((Long) val.elementAt(1)).longValue();
+ }
+ return TIMEOUT;
+ }
+
+ public void setTimeout(String hostname, long timeout) {
+ Vector val = (Vector) get(hostname);
+
+ if (val == null) {
+ val = new Vector();
+ put(hostname, val);
+ }
+ val.setElementAt(Long.valueOf(timeout), 1);
+ }
+
+ public String getSecret(String hostname) {
+ Vector val = (Vector) get(hostname);
+
+ if (val != null) {
+ return (String) val.elementAt(2);
+ }
+ return null;
+ }
+
+ public void setSecret(String hostname, String secret) {
+ Vector val = (Vector) get(hostname);
+
+ if (val == null) {
+ val = new Vector();
+ put(hostname, val);
+ }
+ val.setElementAt(secret, 2);
+ }
+
+ public long getLastLogin(String hostname) {
+ Vector val = (Vector) get(hostname);
+
+ if (val != null) {
+ return ((Long) val.elementAt(3)).longValue();
+ }
+ return LASTLOGIN;
+ }
+
+ public void setLastLogin(String hostname, long lastLogin) {
+ Vector val = (Vector) get(hostname);
+
+ if (val == null) {
+ val = new Vector();
+ put(hostname, val);
+ }
+ val.setElementAt(Long.valueOf(lastLogin), 3);
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/HashAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/HashAuthentication.java
new file mode 100644
index 000000000..12ea8f041
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/HashAuthentication.java
@@ -0,0 +1,290 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+
+// cert server imports.
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.cmsutil.util.*;
+
+// cert server x509 imports
+import netscape.security.x509.*;
+import java.security.cert.*;
+import java.security.*;
+
+// java sdk imports.
+import java.util.*;
+import java.io.IOException;
+
+
+/**
+ * Hash uid/pwd directory based authentication manager
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class HashAuthentication implements IAuthManager, IExtendedPluginInfo {
+
+ public static final String SALT = "lala123";
+ public static final String CRED_UID = "uid";
+ public static final String CRED_FINGERPRINT = "fingerprint";
+ public static final String CRED_PAGEID = "pageID";
+ public static final String CRED_HOST = "hostname";
+ protected static String[] mRequiredCreds = { CRED_UID,
+ CRED_PAGEID, CRED_FINGERPRINT, CRED_HOST };
+ public static final long DEFAULT_TIMEOUT = 600000;
+ private boolean mEnable = false;
+ private long mTimeout = DEFAULT_TIMEOUT; // in milliseconds
+ private String mSecret;
+ private int mPageID;
+ private String mHost;
+ private long mLastLogin = 0;
+ private MessageDigest mSHADigest = null;
+ private Hashtable mData = null;
+ private IConfigStore mConfig;
+ private String mName = null;
+ private String mImplName = null;
+ private ILogger mLogger = CMS.getLogger();
+ private static Vector mExtendedPluginInfo = null;
+ private HashAuthData mHosts = null;
+
+ static String[] mConfigParams =
+ new String[] {};
+
+ static {
+ mExtendedPluginInfo = new Vector();
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TEXT +
+ ";Authenticate the username and password provided " +
+ "by the user against an LDAP directory. Works with the " +
+ "Dir Based Enrollment HTML form");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-authrules-uidpwddirauth");
+ };
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public HashAuthentication() {
+ }
+
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+ mData = new Hashtable();
+ mHosts = new HashAuthData();
+
+ try {
+ mSHADigest = MessageDigest.getInstance("SHA1");
+ } catch (NoSuchAlgorithmException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.getMessage()));
+ }
+
+ }
+
+ public IAuthToken getAuthToken(String key) {
+ return (IAuthToken) mData.remove(key);
+ }
+
+ public void addAuthToken(String pageID, IAuthToken token) {
+ mData.put(pageID, token);
+ }
+
+ public void deleteToken(String pageID) {
+ IAuthToken token = (IAuthToken) mData.remove(pageID);
+ }
+
+ public HashAuthData getData() {
+ return mHosts;
+ }
+
+ public void createEntry(String host, String dn, long timeout,
+ String secret, long lastLogin) {
+ Vector v = new Vector();
+
+ v.addElement(dn);
+ v.addElement(Long.valueOf(timeout));
+ v.addElement(secret);
+ v.addElement(Long.valueOf(lastLogin));
+ mHosts.put(host, v);
+ }
+
+ public void disable(String hostname) {
+ mHosts.remove(hostname);
+ }
+
+ public String getAgentName(String hostname) {
+ return mHosts.getAgentName(hostname);
+ }
+
+ public void setAgentName(String hostname, String agentName) {
+ mHosts.setAgentName(hostname, agentName);
+ }
+
+ public boolean isEnable(String hostname) {
+ return mHosts.containsKey(hostname);
+ }
+
+ public long getTimeout(String hostname) {
+ return mHosts.getTimeout(hostname);
+ }
+
+ public void setTimeout(String hostname, long timeout) {
+ mHosts.setTimeout(hostname, timeout);
+ }
+
+ public String getSecret(String hostname) {
+ return mHosts.getSecret(hostname);
+ }
+
+ public void setSecret(String hostname, String secret) {
+ mHosts.setSecret(hostname, secret);
+ }
+
+ public long getLastLogin(String hostname) {
+ return mHosts.getLastLogin(hostname);
+ }
+
+ public void setLastLogin(String hostname, long lastlogin) {
+ mHosts.setLastLogin(hostname, lastlogin);
+ }
+
+ public long getPageID() {
+ Date date = new Date();
+
+ return date.getTime();
+ }
+
+ public void log(int level, String msg) {
+ if (mLogger == null)
+ return;
+ mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_AUTHENTICATION,
+ level, msg);
+ }
+
+ public boolean validFingerprint(String host, String pageID, String uid, String fingerprint) {
+ String val = hashFingerprint(host, pageID, uid);
+
+ if (val.equals(fingerprint))
+ return true;
+ return false;
+ }
+
+ public Enumeration getHosts() {
+ return mHosts.keys();
+ }
+
+ public String hashFingerprint(String host, String pageID, String uid) {
+ byte[] hash =
+ mSHADigest.digest((SALT + pageID + getSecret(host) + uid).getBytes());
+ String b64E = com.netscape.osutil.OSUtil.BtoA(hash);
+
+ return "{SHA}" + b64E;
+ }
+
+ public void shutdown() {
+ }
+
+ /**
+ * Authenticates a user based on uid, pwd in the directory.
+ *
+ * @param authCreds The authentication credentials.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the uid and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ public IAuthToken authenticate(IAuthCredentials authCreds)
+ throws EBaseException {
+ AuthToken token = new AuthToken(this);
+ String fingerprint = (String) authCreds.get(CRED_FINGERPRINT);
+ String pageID = (String) authCreds.get(CRED_PAGEID);
+ String uid = (String) authCreds.get(CRED_UID);
+ String host = (String) authCreds.get(CRED_HOST);
+
+ if (fingerprint.equals("") ||
+ !validFingerprint(host, pageID, uid, fingerprint)) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_INVALID_FINGER_PRINT"));
+ throw new EAuthException("Invalid Fingerprint");
+ }
+
+ // set uid in the token.
+ token.set(CRED_UID, uid);
+
+ return token;
+ }
+
+ /**
+ * Returns array of required credentials for this authentication manager.
+ * @return Array of required credentials.
+ */
+ public String[] getRequiredCreds() {
+ return mRequiredCreds;
+ }
+
+ /**
+ * Gets the configuration substore used by this authentication manager
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ /**
+ * gets the name of this authentication manager instance
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * gets the plugin name of this authentication manager.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] s = Utils.getStringArrayFromVector(mExtendedPluginInfo);
+
+ return s;
+
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/PortalEnroll.java b/pki/base/common/src/com/netscape/cms/authentication/PortalEnroll.java
new file mode 100644
index 000000000..9f49c2fd1
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/PortalEnroll.java
@@ -0,0 +1,458 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+
+// cert server imports.
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.BaseResources;
+import com.netscape.certsrv.base.EPropertyNotFound;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.base.*;
+
+// java sdk imports.
+import java.util.Locale;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import java.io.IOException;
+
+
+/**
+ * uid/pwd directory based authentication manager
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class PortalEnroll extends DirBasedAuthentication {
+
+ /* configuration parameter keys */
+ protected static final String PROP_LDAPAUTH = "ldapauth";
+ protected static final String PROP_AUTHTYPE = "authtype";
+ protected static final String PROP_BINDDN = "bindDN";
+ protected static final String PROP_BINDPW = "bindPW";
+ protected static final String PROP_LDAPCONN = "ldapconn";
+ protected static final String PROP_HOST = "host";
+ protected static final String PROP_PORT = "port";
+ protected static final String PROP_SECURECONN = "secureConn";
+ protected static final String PROP_VERSION = "version";
+ protected static final String PROP_OBJECTCLASS = "objectclass";
+
+ /* required credentials to authenticate. uid and pwd are strings. */
+ public static final String CRED_UID = "uid";
+ public static final String CRED_PWD = "userPassword";
+ protected static String[] mRequiredCreds = { CRED_UID, CRED_PWD };
+
+ /* ldap configuration sub-store */
+ private IArgBlock argblk = null;
+ private String mObjectClass = null;
+ private String mBindDN = null;
+ private String mBaseDN = null;
+ private ILdapConnFactory mLdapFactory = null;
+ private LDAPConnection mLdapConn = null;
+
+ // contains all nested superiors' required attrs in the form of a
+ // vector of "required" attributes in Enumeration
+ Vector mRequiredAttrs = null;
+
+ // contains all nested superiors' optional attrs in the form of a
+ // vector of "optional" attributes in Enumeration
+ Vector mOptionalAttrs = null;
+
+ // contains all the objclasses, including superiors and itself
+ Vector mObjClasses = null;
+
+ /* Holds configuration parameters 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.
+ */
+ protected static String[] mConfigParams =
+ new String[] {
+ PROP_DNPATTERN,
+ "ldap.ldapconn.host",
+ "ldap.ldapconn.port",
+ "ldap.ldapconn.secureConn",
+ "ldap.ldapconn.version",
+ "ldap.ldapauth.bindDN",
+ "ldap.ldapauth.bindPWPrompt",
+ "ldap.ldapauth.clientCertNickname",
+ "ldap.ldapauth.authtype",
+ "ldap.basedn",
+ "ldap.objectclass",
+ "ldap.minConns",
+ "ldap.maxConns",
+ };
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public PortalEnroll()
+ throws EBaseException {
+ super();
+ }
+
+ /**
+ * Initializes the PortalEnrollment auth manager.
+ * <p>
+ * @param name - The name for this authentication manager instance.
+ * @param implName - The name of the authentication manager plugin.
+ * @param config - The configuration store for this instance.
+ * @exception EBaseException If an error occurs during initialization.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ super.init(name, implName, config);
+
+ /* Get Bind DN for directory server */
+ mConfig = mLdapConfig.getSubStore(PROP_LDAPAUTH);
+ mBindDN = mConfig.getString(PROP_BINDDN);
+ if ( (mBindDN == null) || (mBindDN.length() == 0) || (mBindDN == ""))
+ throw new EPropertyNotFound(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", "binddn"));
+
+ /* Get Bind DN for directory server */
+ mBaseDN = mLdapConfig.getString(PROP_BASEDN);
+ if ((mBaseDN == null) || (mBaseDN.length() == 0) || (mBaseDN == ""))
+ throw new EPropertyNotFound(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", "basedn"));
+
+ /* Get Object clase name for enrollment */
+ mObjectClass = mLdapConfig.getString(PROP_OBJECTCLASS);
+ if (mObjectClass == null || mObjectClass.length() == 0)
+ throw new EPropertyNotFound(CMS.getUserMessage("CMS_BASE_GET_PROPERTY_FAILED", "objectclass"));
+
+ /* Get connect parameter */
+ mLdapFactory = CMS.getLdapBoundConnFactory();
+ mLdapFactory.init(mLdapConfig);
+ mLdapConn = mLdapFactory.getConn();
+
+ log(ILogger.LL_INFO, CMS.getLogMessage("CMS_AUTH_PORTAL_INIT"));
+ }
+
+ /**
+ * Authenticates a user based on uid, pwd in the directory.
+ *
+ * @param authCreds The authentication credentials.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the uid and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected String authenticate(LDAPConnection conn,
+ IAuthCredentials authCreds,
+ AuthToken token)
+ throws EBaseException {
+ String uid = null;
+ String pwd = null;
+ String dn = null;
+
+ argblk = authCreds.getArgBlock();
+
+ // authenticate by binding to ldap server with password.
+ try {
+ // get the uid.
+ uid = (String) authCreds.get(CRED_UID);
+ if (uid == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_UID));
+ }
+
+ // get the password.
+ pwd = (String) authCreds.get(CRED_PWD);
+ if (pwd == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_PWD));
+ }
+ if (pwd.equals("")) {
+ // anonymous binding not allowed
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // get user dn.
+ LDAPSearchResults res = conn.search(mBaseDN,
+ LDAPv2.SCOPE_SUB, "(uid=" + uid + ")", null, false);
+
+ if (res.hasMoreElements()) {
+ LDAPEntry entry = (LDAPEntry) res.nextElement();
+
+ throw new EAuthUserError(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_ATTRIBUTE_VALUE", "UID already exists."));
+ } else {
+ dn = regist(token, uid);
+ if (dn == null)
+ throw new EAuthUserError(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_ATTRIBUTE_VALUE","Could not add user " + uid + "."));
+ }
+
+ // bind as user dn and pwd - authenticates user with pwd.
+ conn.authenticate(dn, pwd);
+
+ // set uid in the token.
+ token.set(CRED_UID, uid);
+
+ log(ILogger.LL_INFO, "portal authentication is done");
+
+ return dn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.toString()));
+ throw e;
+ } catch (LDAPException e) {
+ switch (e.getLDAPResultCode()) {
+ case LDAPException.NO_SUCH_OBJECT:
+ case LDAPException.LDAP_PARTIAL_RESULTS:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_ADD_USER_ERROR", conn.getHost(), Integer.toString(conn.getPort())));
+ throw new
+ EAuthInternalError(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", "Check Configuration detail."));
+
+ case LDAPException.INVALID_CREDENTIALS:
+ log(ILogger.LL_SECURITY,
+ CMS.getLogMessage("CMS_AUTH_BAD_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.SERVER_DOWN:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_SERVER_DOWN"));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+
+ default:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.getMessage()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_OTHER_LDAP_EXCEPTION",
+ e.errorCodeToString()));
+ }
+ } catch (EBaseException e) {
+ if (e.getMessage().equalsIgnoreCase(CMS.getUserMessage("CMS_BASE_ATTRIBUTE_NOT_FOUND")) == true)
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_MAKE_DN_ERROR", e.toString()));
+ throw e;
+ }
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ public String[] getExtendedPluginInfo(Locale locale) {
+ String[] s = {
+ PROP_DNPATTERN + ";string;Template for cert" +
+ " Subject Name. ($dn.xxx - get value from user's LDAP " +
+ "DN. $attr.yyy - get value from LDAP attributes in " +
+ "user's entry.) Default: " + DEFAULT_DNPATTERN,
+ "ldap.ldapconn.host;string,required;" + "LDAP host to connect to",
+ "ldap.ldapconn.port;number,required;" + "LDAP port number (default 389, or 636 if SSL)",
+ "ldap.objectclass;string,required;SEE DOCUMENTATION for Object Class. "
+ + "Default is inetOrgPerson.",
+ "ldap.ldapconn.secureConn;boolean;" + "Use SSL to connect to directory?",
+ "ldap.ldapconn.version;choice(3,2);" + "LDAP protocol version",
+ "ldap.ldapauth.bindDN;string,required;DN to bind as for Directory Manager. "
+ + "For example 'CN=Directory Manager'",
+ "ldap.ldapauth.bindPWPrompt;password;Enter password used to bind as " +
+ "the above user",
+ "ldap.ldapauth.authtype;choice(BasicAuth,SslClientAuth);"
+ + "How to bind to the directory (for pin removal only)",
+ "ldap.ldapauth.clientCertNickname;string;If you want to use "
+ + "SSL client auth to the directory, set the client "
+ + "cert nickname here",
+ "ldap.basedn;string,required;Base DN to start searching " +
+ "under. If your user's DN is 'uid=jsmith, o=company', you " +
+ "might want to use 'o=company' here",
+ "ldap.minConns;number;number of connections " +
+ "to keep open to directory server",
+ "ldap.maxConns;number;when needed, connection " +
+ "pool can grow to this many connections",
+ IExtendedPluginInfo.HELP_TEXT +
+ ";This authentication plugin checks to see if a user " +
+ "exists in the directory. If not, then the user is created " +
+ "with the requested password.",
+ IExtendedPluginInfo.HELP_TOKEN + ";configuration-authrules-portalauth"
+ };
+
+ return s;
+ }
+
+ /**
+ * Returns array of required credentials for this authentication manager.
+ * @return Array of required credentials.
+ */
+ public String[] getRequiredCreds() {
+ return mRequiredCreds;
+ }
+
+ /**
+ * adds a user to the directory.
+ * @return dn upon success and null upon failure.
+ * @param token authentication token
+ * @param uid the user's id.
+ */
+ public String regist(AuthToken token, String uid) {
+ String dn = "uid=" + uid + "," + mBaseDN;
+
+ /* Specify the attributes of the entry */
+ Vector objectclass_values = null;
+
+ LDAPAttributeSet attrs = new LDAPAttributeSet();
+ LDAPAttribute attr = new LDAPAttribute("objectclass");
+
+ // initialized to new
+ mRequiredAttrs = new Vector();
+ mOptionalAttrs = new Vector();
+ mObjClasses = new Vector();
+
+ LDAPSchema dirSchema = null;
+
+ try {
+
+ /* Construct a new LDAPSchema object to hold
+ the schema that you want to retrieve. */
+ dirSchema = new LDAPSchema();
+
+ /* Get the schema from the Directory. Anonymous access okay. */
+ dirSchema.fetchSchema(mLdapConn);
+ } catch (LDAPException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.getMessage()));
+ }
+ // complete mRequiredAttrs, mOptionalAttrs, and mObjClasses
+ initLdapAttrs(dirSchema, mObjectClass);
+
+ objectclass_values = mObjClasses;
+ for (int i = objectclass_values.size() - 1; i >= 0; i--)
+ attr.addValue((String) objectclass_values.elementAt(i));
+ attrs.add(attr);
+
+ Enumeration objClasses = mRequiredAttrs.elements();
+ Enumeration attrnames = null;
+
+ while (objClasses.hasMoreElements()) {
+ attrnames = (Enumeration) objClasses.nextElement();
+ CMS.debug("PortalEnroll: Required attrs:");
+ while (attrnames.hasMoreElements()) {
+ String attrname = (String) attrnames.nextElement();
+ String attrval = null;
+
+ CMS.debug("PortalEnroll: attrname is: " + attrname);
+ if (attrname.equalsIgnoreCase("objectclass") == true)
+ continue;
+ try {
+ attrval = (String) argblk.getValueAsString(attrname);
+ } catch (EBaseException e) {
+ if (e.getMessage().equalsIgnoreCase(CMS.getUserMessage("CMS_BASE_ATTRIBUTE_NOT_FOUND")) == true)
+ continue;
+ }
+
+ CMS.debug("PortalEnroll: " + attrname + " = " + attrval);
+ attrs.add(new LDAPAttribute(attrname, attrval));
+ }
+
+ }
+
+ objClasses = mOptionalAttrs.elements();
+ attrnames = null;
+
+ while (objClasses.hasMoreElements()) {
+ attrnames = (Enumeration) objClasses.nextElement();
+ CMS.debug("PortalEnroll: Optional attrs:");
+ while (attrnames.hasMoreElements()) {
+ String attrname = (String) attrnames.nextElement();
+ String attrval = null;
+
+ CMS.debug("PortalEnroll: attrname is: " + attrname);
+ try {
+ attrval = (String) argblk.getValueAsString(attrname);
+ } catch (EBaseException e) {
+ if (e.getMessage().equalsIgnoreCase(CMS.getUserMessage("CMS_BASE_ATTRIBUTE_NOT_FOUND")) == true)
+ continue;
+ }
+ CMS.debug("PortalEnroll: " + attrname + " = " + attrval);
+ if (attrval != null) {
+ attrs.add(new LDAPAttribute(attrname, attrval));
+ }
+ }
+ }
+
+ /* Create an entry with this DN and these attributes */
+ LDAPEntry entry = new LDAPEntry(dn, attrs);
+
+ try {
+
+ /* Now add the entry to the directory */
+ mLdapConn.add(entry);
+ } catch (LDAPException e) {
+ if (e.getLDAPResultCode() == LDAPException.ENTRY_ALREADY_EXISTS) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.getMessage()));
+ } else
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.getMessage()));
+ return null;
+ }
+
+ log(ILogger.LL_INFO, CMS.getLogMessage("CMS_AUTH_REGISTRATION_DONE"));
+
+ return dn;
+ }
+
+ /*
+ * get the superiors of "inetOrgPerson" so the "required
+ * attributes", "optional qttributes", and "object classes" are complete;
+ * should build up
+ * mRequiredAttrs, mOptionalAttrs, and mObjClasses when returned
+ */
+ public void initLdapAttrs(LDAPSchema dirSchema, String oclass) {
+ CMS.debug("PortalEnroll: in initLdapAttrsAttrs");
+ mObjClasses.addElement(oclass);
+ if (oclass.equalsIgnoreCase("top"))
+ return;
+
+ try {
+
+ /* Get and print the def. of the object class. */
+ LDAPObjectClassSchema objClass = dirSchema.getObjectClass(oclass);
+
+ if (objClass != null) {
+ mRequiredAttrs.add(objClass.getRequiredAttributes());
+ mOptionalAttrs.add(objClass.getOptionalAttributes());
+ } else {
+ return;
+ }
+
+ CMS.debug("PortalEnroll: getting superiors for: " + oclass);
+ String superiors[] = objClass.getSuperiors();
+
+ CMS.debug("PortalEnroll: got superiors, superiors.length=" + superiors.length);
+ if (superiors.length == 0)
+ return;
+ for (int i = 0; i < superiors.length; i++) {
+ CMS.debug("Portalenroll: superior" + i + "=" + superiors[i]);
+ objClass = dirSchema.getObjectClass(superiors[i]);
+ initLdapAttrs(dirSchema, superiors[i]);
+ }
+ } catch (Exception e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_ERROR", e.getMessage()));
+ }
+ }
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/RDNPattern.java b/pki/base/common/src/com/netscape/cms/authentication/RDNPattern.java
new file mode 100644
index 000000000..ee011b0e2
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/RDNPattern.java
@@ -0,0 +1,227 @@
+// --- 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.authentication;
+
+
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.publish.*;
+import netscape.ldap.*;
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * class for parsing a DN pattern used to construct a certificate
+ * subject name from ldap attributes and dn.<p>
+ *
+ * dnpattern is a string representing a subject name pattern to formulate from
+ * the directory attributes and entry dn. If empty or not set, the
+ * ldap entry DN will be used as the certificate subject name. <p>
+ *
+ * The syntax is
+ * <pre>
+ * dnPattern := rdnPattern *[ "," rdnPattern ]
+ * rdnPattern := avaPattern *[ "+" avaPattern ]
+ * avaPattern := name "=" value |
+ * name "=" "$attr" "." attrName [ "." attrNumber ] |
+ * name "=" "$dn" "." attrName [ "." attrNumber ] |
+ * "$dn" "." "$rdn" "." number
+ * </pre>
+ * <pre>
+ * Example1: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US </i>
+ * Ldap entry: dn: UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example2: <i>E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US
+ * <p>
+ * E = the first 'mail' ldap attribute value in user's entry. <br>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * <pre>
+ * Example3: <i>CN=$attr.cn, $rdn.2, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * followed by the second RDN in the user's entry DN. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * Example4: <i>CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US</i>
+ * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James
+ * Ldap attributes: mail: jjames@acme.org
+ * <p>
+ * The subject name formulated will be : <br>
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US
+ * <p>
+ * CN = the (first) 'cn' ldap attribute value in the user's entry. <br>
+ * OU = the second 'ou' value in the user's entry DN followed by the
+ * first 'ou' value in the user's entry. note multiple AVAs
+ * in a RDN in this example. <br>
+ * O = the (first) 'o' value in the user's entry DN. <br>
+ * C = the string "US"
+ * <p>
+ * </pre>
+ * If an attribute or subject DN component does not exist the attribute
+ * is skipped.
+ *
+ * @version $Revision$, $Date$
+ */
+class RDNPattern {
+
+ /* ldap attributes needed by this RDN (to retrieve from ldap) */
+ private String[] mLdapAttrs = null;
+
+ /* AVA patterns */
+ protected AVAPattern[] 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 EBaseException If parsing error occurs.
+ */
+ public RDNPattern(String pattern)
+ throws EAuthException {
+ if (pattern == null || pattern.equals("")) {
+ // create an attribute list that is the dn.
+ mLdapAttrs = new String[] { "dn" };
+ } else {
+ mPatternString = pattern;
+ PushbackReader in = new PushbackReader(new StringReader(pattern));
+
+ parse(in);
+ }
+ }
+
+ /**
+ * Construct a DN pattern from a input stream of pattern
+ */
+ public RDNPattern(PushbackReader in)
+ throws EAuthException {
+ parse(in);
+ }
+
+ private void parse(PushbackReader in)
+ throws EAuthException {
+ //System.out.println("_________ begin rdn _________");
+ Vector avaPatterns = new Vector();
+ AVAPattern avaPattern = null;
+ int lastChar;
+
+ do {
+ avaPattern = new AVAPattern(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 EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ }
+ while (lastChar == '+');
+
+ if (lastChar != -1) {
+ try {
+ in.unread(lastChar); // pushback last ,
+ } catch (IOException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.toString()));
+ }
+ }
+
+ mAVAPatterns = new AVAPattern[avaPatterns.size()];
+ avaPatterns.copyInto(mAVAPatterns);
+
+ Vector ldapAttrs = new Vector();
+
+ for (int i = 0; i < mAVAPatterns.length; i++) {
+ String avaAttr = mAVAPatterns[i].getLdapAttr();
+
+ if (avaAttr == null || avaAttr.length() == 0)
+ continue;
+ ldapAttrs.addElement(avaAttr);
+ }
+ mLdapAttrs = new String[ldapAttrs.size()];
+ ldapAttrs.copyInto(mLdapAttrs);
+ }
+
+ /**
+ * Form a Ldap v3 DN string from results of a ldap search.
+ * @param entry LDAPentry from a ldap search
+ * @return Ldap v3 DN string to use for a subject name.
+ */
+ public String formRDN(LDAPEntry entry)
+ throws EAuthException {
+ StringBuffer formedRDN = new StringBuffer();
+
+ for (int i = 0; i < mAVAPatterns.length; i++) {
+ if (mTestDN != null)
+ mAVAPatterns[i].mTestDN = mTestDN;
+ String ava = mAVAPatterns[i].formAVA(entry);
+
+ 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[] getLdapAttrs() {
+ return (String[]) mLdapAttrs.clone();
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java
new file mode 100644
index 000000000..7a3993cde
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java
@@ -0,0 +1,353 @@
+// --- 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) 2008 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.authentication;
+
+
+import netscape.ldap.*;
+import java.util.*;
+import java.lang.Class;
+import java.security.cert.*;
+import java.security.Principal;
+import netscape.security.x509.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.usrgrp.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.dbs.certdb.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.policy.*;
+
+import com.netscape.certsrv.ca.*;
+import com.netscape.certsrv.ra.*;
+import com.netscape.certsrv.kra.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+
+/**
+ * Certificate server SSL client authentication.
+ *
+ * @author Christina Fu
+ * <P>
+ *
+ */
+public class SSLclientCertAuthentication implements IAuthManager,
+ IProfileAuthenticator {
+
+ /* result auth token attributes */
+ public static final String TOKEN_USERDN = "user";
+ public static final String TOKEN_USER_DN = "userdn";
+ public static final String TOKEN_USERID = "userid";
+ public static final String TOKEN_UID = "uid";
+
+ /* required credentials */
+ public static final String CRED_CERT = IAuthManager.CRED_SSL_CLIENT_CERT;
+ protected String[] mRequiredCreds = { CRED_CERT };
+
+ /* config parameters to pass to console (none) */
+ protected static String[] mConfigParams = null;
+
+ private String mName = null;
+ private String mImplName = null;
+ private IConfigStore mConfig = null;
+
+ private ILogger mLogger = CMS.getLogger();
+
+ private IConfigStore mRevocationChecking = null;
+ private String mRequestor = null;
+
+ public SSLclientCertAuthentication() {
+ }
+
+ /**
+ * initializes the SSLClientCertAuthentication auth manager
+ * <p>
+ * called by AuthSubsystem init() method, when initializing
+ * all available authentication managers.
+ * @param name The name of this authentication manager instance.
+ * @param implName The name of the authentication manager plugin.
+ * @param config The configuration store for this authentication manager.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+ }
+
+ /**
+ * Gets the name of this authentication manager.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the plugin name of authentication manager.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ public boolean isSSLClientRequired() {
+ return true;
+ }
+
+ /**
+ * authenticates user by certificate
+ * <p>
+ * called by other subsystems or their servlets to authenticate
+ * users
+ * @param authCred - authentication credential that contains
+ * an usrgrp.Certificates of the user (agent)
+ * @return the authentication token that contains the following
+ *
+ * @exception EMissingCredential If a required credential for this
+ * authentication manager is missing.
+ * @exception EInvalidCredentials If credentials cannot be authenticated.
+ * @exception EBaseException If an internal error occurred.
+ * @see com.netscape.certsrv.authentication.AuthToken
+ * @see com.netscape.certsrv.usrgrp.Certificates
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+
+ CMS.debug("SSLclientCertAuthentication: start");
+ CMS.debug("authenticator instance name is "+getName());
+
+ // force SSL handshake
+ SessionContext context = SessionContext.getExistingContext();
+ ISSLClientCertProvider provider = (ISSLClientCertProvider)
+ context.get("sslClientCertProvider");
+
+ if (provider == null) {
+ CMS.debug("SSLclientCertAuthentication: No SSL Client Cert Provider Found");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ CMS.debug("SSLclientCertAuthentication: got provider");
+ CMS.debug("SSLclientCertAuthentication: retrieving client certificate");
+ X509Certificate[] allCerts = provider.getClientCertificateChain();
+
+ if (allCerts == null) {
+ CMS.debug("SSLclientCertAuthentication: No SSL Client Certs Found");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ CMS.debug("SSLclientCertAuthentication: got certificates");
+
+ // retreive certificate from socket
+ AuthToken authToken = new AuthToken(this);
+ X509Certificate[] x509Certs = allCerts;
+
+ // default certificate default has bugs in version
+ // version(3) is returned as 3, which should be 2
+ X509CertImpl ci[] = new X509CertImpl[x509Certs.length];
+
+ X509Certificate clientCert = null;
+ try {
+ for (int i = 0; i < x509Certs.length; i++) {
+ ci[i] = new X509CertImpl(x509Certs[i].getEncoded());
+ // find out which one is the leaf cert
+ clientCert = ci[i];
+
+ byte [] extBytes = clientCert.getExtensionValue("2.5.29.19");
+ // try to see if this is a leaf cert
+ // look for BasicConstraint extension
+ if (extBytes == null) {
+ // found leaf cert
+ CMS.debug("SSLclientCertAuthentication: authenticate: found leaf cert");
+ break;
+ } else {
+ CMS.debug("SSLclientCertAuthentication: authenticate: found cert having BasicConstraints ext");
+ // it's got BasicConstraints extension
+ // so it's not likely to be a leaf cert,
+ // however, check the isCA field regardless
+ try {
+ BasicConstraintsExtension bce =
+ new BasicConstraintsExtension(true, extBytes);
+ if (bce != null) {
+ if (!(Boolean)bce.get("is_ca")) {
+ CMS.debug("SSLclientCertAuthentication: authenticate: found CA cert in chain");
+ break;
+ } // else found a ca cert, continue
+ }
+ } catch (Exception e) {
+ CMS.debug("SSLclientCertAuthentication: authenticate: exception:"+
+ e.toString());
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ }
+ }
+ if (clientCert == null) {
+ CMS.debug("SSLclientCertAuthentication: authenticate: client cert not found");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ } catch (CertificateException e) {
+ CMS.debug(e.toString());
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // check if certificate(s) is revoked
+ boolean checkRevocation = true;
+ try {
+ checkRevocation = mConfig.getBoolean("checkRevocation", true);
+ } catch (EBaseException e) {
+ // do nothing; default to true
+ }
+ if (checkRevocation) {
+ if (CMS.isRevoked(ci)) {
+ CMS.debug("SSLclientCertAuthentication: certificate revoked");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ }
+ Certificates certs = new Certificates(ci);
+ Principal p_dn = clientCert.getSubjectDN();
+ authToken.set(TOKEN_USERDN, p_dn.getName());
+ authToken.set("userdn", p_dn.getName());
+ String uid = getUidFromDN(p_dn.getName());
+ if (uid != null) {
+ authToken.set(TOKEN_UID, uid);
+ authToken.set(TOKEN_USERID, uid);
+ }
+/*
+ authToken.set(TOKEN_USER_DN, user.getUserDN());
+ authToken.set(TOKEN_USERID, user.getUserID());
+ authToken.set(TOKEN_UID, user.getUserID());
+ authToken.set(TOKEN_GROUP, groupname);
+*/
+ authToken.set(CRED_CERT, certs);
+
+ CMS.debug("SSLclientCertAuthentication: authenticated ");
+
+ return authToken;
+ }
+
+ String getUidFromDN(String userdn) {
+ StringTokenizer st = new StringTokenizer(userdn, ",");
+ while (st.hasMoreTokens()) {
+ String t = st.nextToken();
+ int i = t.indexOf("=");
+
+ if (i == -1) {
+ continue;
+ }
+ String n = t.substring(0, i);
+ if (n.equalsIgnoreCase("uid")) {
+ String v = t.substring(i + 1);
+ CMS.debug("SSLclientCertAuthentication: getUidFromDN(): uid found:"+v);
+ return v;
+ } else {
+ continue;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get the list of authentication credential attribute names
+ * required by this authentication manager. Generally used by
+ * the servlets that handle agent operations to authenticate its
+ * users. It calls this method to know which are the
+ * required credentials from the user (e.g. Javascript form data)
+ * @return attribute names in Vector
+ */
+ public String[] getRequiredCreds() {
+ return (mRequiredCreds);
+ }
+
+ /**
+ * get the list of configuration parameter names
+ * required by this authentication manager. Generally used by
+ * the Certificate Server Console to display the table for
+ * configuration purposes. CertUserDBAuthentication is currently not
+ * exposed in this case, so this method is not to be used.
+ * @return configuration parameter names in Hashtable of Vectors
+ * where each hashtable entry's key is the substore name, value is a
+ * Vector of parameter names. If no substore, the parameter name
+ * is the Hashtable key itself, with value same as key.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * prepare this authentication manager for shutdown.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * gets the configuretion substore used by this authentication
+ * manager
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_SSL_CLIENT_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_SSL_CLIENT_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ return null;
+ }
+
+ public boolean isValueWriteable(String name) {
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ request.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME,
+ token.getInString(TOKEN_USERDN));
+ request.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME,
+ token.getInString("userDN"));
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/SharedSecret.java b/pki/base/common/src/com/netscape/cms/authentication/SharedSecret.java
new file mode 100644
index 000000000..98bf72f47
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/SharedSecret.java
@@ -0,0 +1,36 @@
+// --- 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.authentication;
+
+import java.math.BigInteger;
+import org.mozilla.jss.pkix.cmc.PKIData;
+import com.netscape.certsrv.authentication.ISharedToken;
+
+public class SharedSecret implements ISharedToken {
+
+ public SharedSecret() {
+ }
+
+ public String getSharedToken(PKIData cmcdata) {
+ return "testing";
+ }
+
+ public String getSharedToken(BigInteger serial) {
+ return "testing";
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/TokenAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/TokenAuthentication.java
new file mode 100644
index 000000000..937531933
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/TokenAuthentication.java
@@ -0,0 +1,298 @@
+// --- 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.authentication;
+
+import java.io.*;
+import java.util.*;
+import java.lang.Class;
+import java.security.cert.*;
+import netscape.security.x509.*;
+import com.netscape.certsrv.base.*;
+import com.netscape.certsrv.common.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.usrgrp.*;
+import com.netscape.certsrv.logging.*;
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.dbs.certdb.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.policy.*;
+import com.netscape.cmsutil.http.*;
+import com.netscape.certsrv.ca.*;
+import com.netscape.certsrv.ra.*;
+import com.netscape.certsrv.kra.*;
+import javax.servlet.http.HttpServletRequest;
+import com.netscape.cmsutil.xml.*;
+import org.w3c.dom.*;
+
+/**
+ * Token authentication.
+ * Checked if the given token is valid.
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class TokenAuthentication implements IAuthManager,
+ IProfileAuthenticator {
+
+ /* result auth token attributes */
+ public static final String TOKEN_UID = "uid";
+ public static final String TOKEN_GID = "gid";
+
+ /* required credentials */
+ public static final String CRED_SESSION_ID = IAuthManager.CRED_SESSION_ID;
+ protected String[] mRequiredCreds = { CRED_SESSION_ID };
+
+ /* config parameters to pass to console (none) */
+ protected static String[] mConfigParams = null;
+
+ private String mName = null;
+ private String mImplName = null;
+ private IConfigStore mConfig = null;
+
+ private IUGSubsystem mUGSub = null;
+ private ILogger mLogger = CMS.getLogger();
+
+ public TokenAuthentication() {
+ }
+
+ /**
+ * initializes the TokenAuthentication auth manager
+ * <p>
+ * called by AuthSubsystem init() method, when initializing
+ * all available authentication managers.
+ * @param name The name of this authentication manager instance.
+ * @param implName The name of the authentication manager plugin.
+ * @param config The configuration store for this authentication manager.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ mName = name;
+ mImplName = implName;
+ mConfig = config;
+
+ mUGSub = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+ }
+
+ /**
+ * Gets the name of this authentication manager.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Gets the plugin name of authentication manager.
+ */
+ public String getImplName() {
+ return mImplName;
+ }
+
+ public boolean isSSLClientRequired() {
+ return false;
+ }
+
+ /**
+ * authenticates user(agent) by certificate
+ * <p>
+ * called by other subsystems or their servlets to authenticate
+ * users (agents)
+ * @param authCred - authentication credential that contains
+ * an usrgrp.Certificates of the user (agent)
+ * @return the authentication token that contains the following
+ * @exception EMissingCredential If a required credential for this
+ * authentication manager is missing.
+ * @exception EInvalidCredentials If credentials cannot be authenticated.
+ * @exception EBaseException If an internal error occurred.
+ * @see com.netscape.certsrv.authentication.AuthToken
+ * @see com.netscape.certsrv.usrgrp.Certificates
+ */
+ public IAuthToken authenticate(IAuthCredentials authCred)
+ throws EMissingCredential, EInvalidCredentials, EBaseException {
+
+ CMS.debug("TokenAuthentication: start");
+
+ // force SSL handshake
+ SessionContext context = SessionContext.getExistingContext();
+
+ // retreive certificate from socket
+ AuthToken authToken = new AuthToken(this);
+
+ // get group name from configuration file
+ IConfigStore sconfig = CMS.getConfigStore();
+
+ String sessionId = (String)authCred.get(CRED_SESSION_ID);
+ String givenHost = (String)authCred.get("clientHost");
+ String auth_host = sconfig.getString("securitydomain.host");
+ int auth_port = sconfig.getInteger("securitydomain.httpseeport");
+
+ HttpClient httpclient = new HttpClient();
+ String c = null;
+ try {
+ JssSSLSocketFactory factory = new JssSSLSocketFactory();
+ httpclient = new HttpClient(factory);
+ String content = CRED_SESSION_ID+"="+sessionId+"&hostname="+givenHost;
+ CMS.debug("TokenAuthentication: content=" + content);
+ httpclient.connect(auth_host, auth_port);
+ HttpRequest httprequest = new HttpRequest();
+ httprequest.setMethod(HttpRequest.POST);
+ httprequest.setURI("/ca/ee/ca/tokenAuthenticate");
+ httprequest.setHeader("user-agent", "HTTPTool/1.0");
+ httprequest.setHeader("content-length", "" + content.length());
+ httprequest.setHeader("content-type",
+ "application/x-www-form-urlencoded");
+ httprequest.setContent(content);
+ HttpResponse httpresponse = httpclient.send(httprequest);
+
+ c = httpresponse.getContent();
+ } catch (Exception e) {
+ CMS.debug("TokenAuthentication authenticate Exception="+e.toString());
+ }
+
+ if (c != null) {
+ try {
+ ByteArrayInputStream bis = new ByteArrayInputStream(c.getBytes());
+ XMLObject parser = null;
+
+ try {
+ parser = new XMLObject(bis);
+ } catch (Exception e) {
+ CMS.debug( "TokenAuthentication::authenticate() - "
+ + "Exception="+e.toString() );
+ throw new EBaseException( e.toString() );
+ }
+ String status = parser.getValue("Status");
+
+ CMS.debug("TokenAuthentication: status=" + status);
+ if (!status.equals("0")) {
+ String error = parser.getValue("Error");
+ throw new EBaseException(error);
+ }
+
+ String uid = parser.getValue("uid");
+ String gid = parser.getValue("gid");
+
+ authToken.set(TOKEN_UID, uid);
+ authToken.set(TOKEN_GID, gid);
+
+ if(context != null) {
+ CMS.debug("SessionContext.USER_ID " + uid + " SessionContext.GROUP_ID " + gid);
+ context.put(SessionContext.USER_ID, uid );
+ context.put(SessionContext.GROUP_ID, gid );
+ }
+
+ CMS.debug("TokenAuthentication: authenticated uid="+uid+", gid="+gid);
+ } catch (EBaseException e) {
+ throw e;
+ } catch (Exception e) {
+ }
+ }
+
+ return authToken;
+ }
+
+ /**
+ * get the list of authentication credential attribute names
+ * required by this authentication manager. Generally used by
+ * the servlets that handle agent operations to authenticate its
+ * users. It calls this method to know which are the
+ * required credentials from the user (e.g. Javascript form data)
+ * @return attribute names in Vector
+ */
+ public String[] getRequiredCreds() {
+ return (mRequiredCreds);
+ }
+
+ /**
+ * get the list of configuration parameter names
+ * required by this authentication manager. Generally used by
+ * the Certificate Server Console to display the table for
+ * configuration purposes. CertUserDBAuthentication is currently not
+ * exposed in this case, so this method is not to be used.
+ * @return configuration parameter names in Hashtable of Vectors
+ * where each hashtable entry's key is the substore name, value is a
+ * Vector of parameter names. If no substore, the parameter name
+ * is the Hashtable key itself, with value same as key.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * prepare this authentication manager for shutdown.
+ */
+ public void shutdown() {
+ }
+
+ /**
+ * gets the configuretion substore used by this authentication
+ * manager
+ * @return configuration store
+ */
+ public IConfigStore getConfigStore() {
+ return mConfig;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_AGENT_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ Vector v = new Vector();
+
+ v.addElement(CRED_SESSION_ID);
+ return v.elements();
+ }
+
+ public boolean isValueWriteable(String name) {
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java
new file mode 100644
index 000000000..07f072914
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java
@@ -0,0 +1,199 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+
+// cert server imports.
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.apps.*;
+
+// cert server x509 imports
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.CertificateSubjectName;
+import java.security.cert.CertificateException;
+
+// java sdk imports.
+import java.util.Hashtable;
+import java.util.Vector;
+import java.io.IOException;
+
+
+/**
+ * udn/pwd directory based authentication manager
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class UdnPwdDirAuthentication extends DirBasedAuthentication {
+
+ /* required credentials to authenticate. udn and pwd are strings. */
+ public static final String CRED_UDN = "udn";
+ public static final String CRED_PWD = "pwd";
+ protected static String[] mRequiredCreds = { CRED_UDN, CRED_PWD };
+
+ /* Holds configuration parameters 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.
+ */
+ protected static String[] mConfigParams =
+ new String[] { PROP_DNPATTERN,
+ PROP_LDAPSTRINGATTRS,
+ PROP_LDAPBYTEATTRS,
+ "ldap.ldapconn.host",
+ "ldap.ldapconn.port",
+ "ldap.ldapconn.secureConn",
+ "ldap.ldapconn.version",
+ "ldap.minConns",
+ "ldap.maxConns",
+ };
+
+ static {
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TEXT +
+ ";Authenticate the user distinguished name and password provided " +
+ "by the user against an LDAP directory. Works with the " +
+ "Dir Based Enrollment HTML form");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-authentication");
+ };
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public UdnPwdDirAuthentication() {
+ super();
+ }
+
+ /**
+ * Initializes the UdnPwdDirAuthentication auth manager.
+ * <p>
+ * @param name - The name for this authentication manager instance.
+ * @param implName - The name of the authentication manager plugin.
+ * @param config - The configuration store for this instance.
+ * @exception EBaseException If an error occurs during initialization.
+ */
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ super.init(name, implName, config, false);
+ }
+
+ /**
+ * Authenticates a user based on udn, pwd in the directory.
+ *
+ * @param authCreds The authentication credentials.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the udn and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected String authenticate(LDAPConnection conn,
+ IAuthCredentials authCreds,
+ AuthToken token)
+ throws EBaseException {
+ String userdn = null;
+
+ // authenticate by binding to ldap server with password.
+ try {
+ // get the udn.
+ userdn = (String) authCreds.get(CRED_UDN);
+ if (userdn == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_UDN));
+ }
+
+ // get the password.
+ String pwd = (String) authCreds.get(CRED_PWD);
+
+ if (pwd == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_PWD));
+ }
+ if (pwd.equals("")) {
+ // anonymous binding not allowed
+ log(ILogger.LL_FAILURE,
+ "user " + userdn + " attempted login with empty password.");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // bind as user dn and pwd - authenticates user with pwd.
+ conn.authenticate(userdn, pwd);
+ // set userdn in the token.
+ token.set(CRED_UDN, userdn);
+
+ return userdn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE,
+ "Couldn't get ldap connection. Error: " + e.toString());
+ throw e;
+ } catch (LDAPException e) {
+ switch (e.getLDAPResultCode()) {
+ case LDAPException.NO_SUCH_OBJECT:
+ case LDAPException.LDAP_PARTIAL_RESULTS:
+ log(ILogger.LL_SECURITY,
+ "user " + userdn + " does not exist in ldap server host " +
+ conn.getHost() + ", port " + conn.getPort() + ".");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.INVALID_CREDENTIALS:
+ log(ILogger.LL_SECURITY,
+ "authenticate user " + userdn + " with bad password.");
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.SERVER_DOWN:
+ log(ILogger.LL_FAILURE, "Ldap server is down.");
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+
+ default:
+ log(ILogger.LL_FAILURE,
+ "Ldap error encountered. " + e.getMessage());
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_OTHER_LDAP_EXCEPTION",
+ e.errorCodeToString()));
+ }
+ }
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * Returns array of required credentials for this authentication manager.
+ * @return Array of required credentials.
+ */
+ public String[] getRequiredCreds() {
+ return mRequiredCreds;
+ }
+
+}
+
diff --git a/pki/base/common/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
new file mode 100644
index 000000000..41f178163
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java
@@ -0,0 +1,270 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+
+// cert server imports.
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.request.*;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.apps.*;
+
+// cert server x509 imports
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.CertificateSubjectName;
+import java.security.cert.CertificateException;
+
+// java sdk imports.
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Locale;
+import java.util.Enumeration;
+import java.io.IOException;
+
+
+/**
+ * uid/pwd directory based authentication manager
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class UidPwdDirAuthentication extends DirBasedAuthentication
+ implements IProfileAuthenticator {
+
+ /* required credentials to authenticate. uid and pwd are strings. */
+ public static final String CRED_UID = "uid";
+ public static final String CRED_PWD = "pwd";
+ protected static String[] mRequiredCreds = { CRED_UID, CRED_PWD };
+
+ /* Holds configuration parameters 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.
+ */
+ protected static String[] mConfigParams =
+ new String[] { PROP_DNPATTERN,
+ PROP_LDAPSTRINGATTRS,
+ PROP_LDAPBYTEATTRS,
+ "ldap.ldapconn.host",
+ "ldap.ldapconn.port",
+ "ldap.ldapconn.secureConn",
+ "ldap.ldapconn.version",
+ "ldap.basedn",
+ "ldap.minConns",
+ "ldap.maxConns",
+ };
+
+ static {
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TEXT +
+ ";Authenticate the username and password provided " +
+ "by the user against an LDAP directory. Works with the " +
+ "Dir Based Enrollment HTML form");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-authrules-uidpwddirauth");
+ };
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public UidPwdDirAuthentication() {
+ super();
+ }
+
+ /**
+ * Authenticates a user based on uid, pwd in the directory.
+ *
+ * @param authCreds The authentication credentials.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the uid and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected String authenticate(LDAPConnection conn,
+ IAuthCredentials authCreds,
+ AuthToken token)
+ throws EBaseException {
+ String userdn = null;
+ String uid = null;
+
+ // authenticate by binding to ldap server with password.
+ try {
+ // get the uid.
+ uid = (String) authCreds.get(CRED_UID);
+ CMS.debug("Authenticating UID=" + uid);
+ if (uid == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_UID));
+ }
+
+ // get the password.
+ String pwd = (String) authCreds.get(CRED_PWD);
+
+ if (pwd == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL",CRED_PWD));
+ }
+ if (pwd.equals("")) {
+ // anonymous binding not allowed
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_EMPTY_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // get user dn.
+ CMS.debug("Authenticating: Searching for UID=" + uid +
+ " base DN=" + mBaseDN);
+ LDAPSearchResults res = conn.search(mBaseDN,
+ LDAPv2.SCOPE_SUB, "(uid=" + uid + ")", null, false);
+
+ if (res.hasMoreElements()) {
+ //LDAPEntry entry = (LDAPEntry)res.nextElement();
+ LDAPEntry entry = res.next();
+
+ userdn = entry.getDN();
+ CMS.debug("Authenticating: Found User DN=" + userdn);
+ } else {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_USER_NOT_EXIST", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // bind as user dn and pwd - authenticates user with pwd.
+ conn.authenticate(userdn, pwd);
+ // set uid in the token.
+ token.set(CRED_UID, uid);
+
+ return userdn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
+ throw e;
+ } catch (LDAPException e) {
+ switch (e.getLDAPResultCode()) {
+ case LDAPException.NO_SUCH_OBJECT:
+ case LDAPException.LDAP_PARTIAL_RESULTS:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("USER_NOT_EXIST", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.INVALID_CREDENTIALS:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_BAD_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.SERVER_DOWN:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("LDAP_SERVER_DOWN"));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+
+ default:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.getMessage()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_OTHER_LDAP_EXCEPTION",
+ e.errorCodeToString()));
+ }
+ }
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * Returns array of required credentials for this authentication manager.
+ * @return Array of required credentials.
+ */
+ public String[] getRequiredCreds() {
+ return mRequiredCreds;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ Vector v = new Vector();
+
+ v.addElement(CRED_UID);
+ v.addElement(CRED_PWD);
+ return v.elements();
+ }
+
+ public boolean isValueWriteable(String name) {
+ if (name.equals(CRED_UID)) {
+ return true;
+ } else if (name.equals(CRED_PWD)) {
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ if (name.equals(CRED_UID)) {
+ return new Descriptor(IDescriptor.STRING, null, null,
+ CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID"));
+ } else if (name.equals(CRED_PWD)) {
+ return new Descriptor(IDescriptor.PASSWORD, null, null,
+ CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_PWD"));
+
+ }
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ request.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME,
+ token.getInString(USER_DN));
+ }
+
+ public boolean isSSLClientRequired() {
+ return false;
+ }
+}
diff --git a/pki/base/common/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java b/pki/base/common/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java
new file mode 100644
index 000000000..7b6e41da0
--- /dev/null
+++ b/pki/base/common/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java
@@ -0,0 +1,464 @@
+// --- 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.authentication;
+
+
+// ldap java sdk
+import netscape.ldap.*;
+import java.util.*;
+
+// cert server imports.
+import com.netscape.certsrv.apps.*;
+import com.netscape.certsrv.ldap.*;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.ldap.ELdapException;
+import com.netscape.certsrv.ldap.LdapResources;
+import com.netscape.certsrv.logging.ILogger;
+import com.netscape.certsrv.authentication.*;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.common.NameValuePairs;
+import com.netscape.certsrv.profile.*;
+import com.netscape.certsrv.property.*;
+import com.netscape.certsrv.request.*;
+
+// cert server x509 imports
+import netscape.security.x509.X509CertInfo;
+import netscape.security.x509.X500Name;
+import netscape.security.x509.CertificateSubjectName;
+import java.security.cert.CertificateException;
+import java.security.NoSuchAlgorithmException;
+import java.security.MessageDigest;
+
+// java sdk imports.
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.io.IOException;
+import java.io.*;
+
+
+/**
+ * uid/pwd/pin directory based authentication manager
+ * <P>
+ *
+ * @version $Revision$, $Date$
+ */
+public class UidPwdPinDirAuthentication extends DirBasedAuthentication
+ implements IExtendedPluginInfo, IProfileAuthenticator {
+
+ /* required credentials to authenticate. uid and pwd are strings. */
+ public static final String CRED_UID = "uid";
+ public static final String CRED_PWD = "pwd";
+ public static final String CRED_PIN = "pin";
+ protected static String[] mRequiredCreds = { CRED_UID, CRED_PWD, CRED_PIN };
+
+ public static final String PROP_REMOVE_PIN = "removePin";
+ public static final String PROP_PIN_ATTR = "pinAttr";
+
+ public static final boolean DEF_REMOVE_PIN = false;
+ public static final String DEF_PIN_ATTR = "pin";
+
+ protected static final byte SENTINEL_SHA = 0;
+ protected static final byte SENTINEL_MD5 = 1;
+ protected static final byte SENTINEL_NONE = 0x2d;
+
+ /* Holds configuration parameters 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.
+ */
+ protected static String[] mConfigParams =
+ new String[] { PROP_REMOVE_PIN,
+ PROP_PIN_ATTR,
+ PROP_DNPATTERN,
+ PROP_LDAPSTRINGATTRS,
+ PROP_LDAPBYTEATTRS,
+ "ldap.ldapconn.host",
+ "ldap.ldapconn.port",
+ "ldap.ldapconn.secureConn",
+ "ldap.ldapconn.version",
+ "ldap.ldapauth.bindDN",
+ "ldap.ldapauth.bindPWPrompt",
+ "ldap.ldapauth.clientCertNickname",
+ "ldap.ldapauth.authtype",
+ "ldap.basedn",
+ "ldap.minConns",
+ "ldap.maxConns",
+ };
+
+ static {
+ mExtendedPluginInfo.add(
+ PROP_REMOVE_PIN + ";boolean;SEE DOCUMENTATION for pin removal");
+ mExtendedPluginInfo.add(
+ PROP_PIN_ATTR + ";string;directory attribute to use for pin (default 'pin')");
+ mExtendedPluginInfo.add(
+ "ldap.ldapauth.bindDN;string;DN to bind as for pin removal. "
+ + "For example 'CN=PinRemoval User'");
+ mExtendedPluginInfo.add(
+ "ldap.ldapauth.bindPWPrompt;password;Enter password used to bind as " +
+ "the above user");
+ mExtendedPluginInfo.add(
+ "ldap.ldapauth.clientCertNickname;string;If you want to use "
+ + "SSL client auth to the directory, set the client "
+ + "cert nickname here");
+ mExtendedPluginInfo.add(
+ "ldap.ldapauth.authtype;choice(BasicAuth,SslClientAuth),required;"
+ + "How to bind to the directory (for pin removal only)");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TEXT
+ + ";Authenticate the username, password and pin provided "
+ + "by the user against an LDAP directory. Works with the "
+ + "Dir/Pin Based Enrollment HTML form");
+ mExtendedPluginInfo.add(IExtendedPluginInfo.HELP_TOKEN +
+ ";configuration-authrules-uidpwdpindirauth");
+
+ }
+
+ protected boolean mRemovePin = DEF_REMOVE_PIN;
+ protected String mPinAttr = DEF_PIN_ATTR;
+ protected MessageDigest mSHADigest = null;
+ protected MessageDigest mMD5Digest = null;
+
+ private String mBindDN = null;
+ private String mBindPassword = null;
+
+ private ILdapConnFactory removePinLdapFactory = null;
+ private LDAPConnection removePinLdapConnection = null;
+ private IConfigStore removePinLdapConfigStore = null;
+
+ /**
+ * Default constructor, initialization must follow.
+ */
+ public UidPwdPinDirAuthentication() {
+ super();
+ }
+
+ public void init(String name, String implName, IConfigStore config)
+ throws EBaseException {
+ super.init(name, implName, config);
+ mRemovePin =
+ config.getBoolean(PROP_REMOVE_PIN, DEF_REMOVE_PIN);
+ mPinAttr =
+ config.getString(PROP_PIN_ATTR, DEF_PIN_ATTR);
+ if (mPinAttr.equals("")) {
+ mPinAttr = DEF_PIN_ATTR;
+ }
+
+ if (mRemovePin) {
+ removePinLdapConfigStore = config.getSubStore("ldap");
+ removePinLdapFactory = CMS.getLdapBoundConnFactory();
+ removePinLdapFactory.init(removePinLdapConfigStore);
+ removePinLdapConnection = removePinLdapFactory.getConn();
+ }
+
+ try {
+ mSHADigest = MessageDigest.getInstance("SHA1");
+ mMD5Digest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new EAuthException(CMS.getUserMessage("CMS_AUTHENTICATION_INTERNAL_ERROR", e.getMessage()));
+ }
+
+ }
+
+ protected void verifyPassword(String Password) {
+ }
+
+ /**
+ * Authenticates a user based on its uid, pwd, pin in the directory.
+ *
+ * @param authCreds The authentication credentials with uid, pwd, pin.
+ * @return The user's ldap entry dn.
+ * @exception EInvalidCredentials If the uid and password are not valid
+ * @exception EBaseException If an internal error occurs.
+ */
+ protected String authenticate(LDAPConnection conn,
+ IAuthCredentials authCreds,
+ AuthToken token)
+ throws EBaseException {
+ String userdn = null;
+ String uid = null;
+ String pwd = null;
+ String pin = null;
+
+ try {
+ // get the uid.
+ uid = (String) authCreds.get(CRED_UID);
+ if (uid == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_UID));
+ }
+
+ // get the password.
+ pwd = (String) authCreds.get(CRED_PWD);
+ if (pwd == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_PWD));
+ }
+ if (pwd.equals("")) {
+ // anonymous binding not allowed
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_EMPTY_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // get the pin.
+ pin = (String) authCreds.get(CRED_PIN);
+ if (pin == null) {
+ throw new EMissingCredential(CMS.getUserMessage("CMS_AUTHENTICATION_NULL_CREDENTIAL", CRED_PIN));
+ }
+ if (pin.equals("")) {
+ // empty pin not allowed
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_EMPTY_PIN", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // get user dn.
+ LDAPSearchResults res = conn.search(mBaseDN,
+ LDAPv2.SCOPE_SUB, "(uid=" + uid + ")", null, false);
+
+ if (res.hasMoreElements()) {
+ LDAPEntry entry = (LDAPEntry) res.nextElement();
+
+ userdn = entry.getDN();
+ } else {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_USER_NOT_EXIST", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // bind as user dn and pwd - authenticates user with pwd.
+ conn.authenticate(userdn, pwd);
+
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_AUTHENTICATED", uid));
+ // log(ILogger.LL_SECURITY, "found user : " + userdn);
+
+ // check pin.
+ checkpin(conn, userdn, uid, pin);
+
+ // set uid in the token.
+ token.set(CRED_UID, uid);
+
+ return userdn;
+ } catch (ELdapException e) {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CANNOT_CONNECT_LDAP", e.toString()));
+ throw e;
+ } catch (LDAPException e) {
+ switch (e.getLDAPResultCode()) {
+ case LDAPException.NO_SUCH_OBJECT:
+ case LDAPException.LDAP_PARTIAL_RESULTS:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_USER_NOT_EXIST", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.INVALID_CREDENTIALS:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_BAD_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+
+ case LDAPException.SERVER_DOWN:
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("LDAP_SERVER_DOWN"));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_SERVER_UNAVAILABLE", conn.getHost(), "" + conn.getPort()));
+
+ default:
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.getMessage()));
+ throw new ELdapException(
+ CMS.getUserMessage("CMS_LDAP_OTHER_LDAP_EXCEPTION",
+ e.errorCodeToString()));
+ }
+ }
+ }
+
+ protected void checkpin(LDAPConnection conn, String userdn,
+ String uid, String pin)
+ throws EBaseException, LDAPException {
+ LDAPSearchResults res = null;
+ LDAPEntry entry = null;
+
+ // get pin.
+
+ res = conn.search(userdn, LDAPv2.SCOPE_BASE,
+ "(objectclass=*)", new String[] { mPinAttr }, false);
+ if (res.hasMoreElements()) {
+ entry = (LDAPEntry) res.nextElement();
+ } else {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_NO_ENTRY_RETURNED", uid, userdn));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ LDAPAttribute pinAttr = entry.getAttribute(mPinAttr);
+
+ if (pinAttr == null) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ Enumeration pinValues = pinAttr.getByteValues();
+
+ if (!pinValues.hasMoreElements()) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+ byte[] entrypin = (byte[]) pinValues.nextElement();
+
+ // compare value digest.
+
+ if (entrypin == null || entrypin.length < 2) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_NO_PIN_FOUND", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ byte hashtype = entrypin[0];
+
+ byte[] pinDigest = null;
+ String toBeDigested = userdn + pin;
+
+ if (hashtype == SENTINEL_SHA) {
+
+ pinDigest = mSHADigest.digest(toBeDigested.getBytes());
+ } else if (hashtype == SENTINEL_MD5) {
+ pinDigest = mMD5Digest.digest(toBeDigested.getBytes());
+ } else if (hashtype == SENTINEL_NONE) {
+ pinDigest = toBeDigested.getBytes();
+ } else {
+ log(ILogger.LL_FAILURE, CMS.getLogMessage("CMS_AUTH_UKNOWN_ENCODING_TYPE", mPinAttr, "*", userdn));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ if (pinDigest.length != (entrypin.length - 1)) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_LENGTH_NOT_MATCHED", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ int i;
+
+ for (i = 0; i < (entrypin.length - 1); i++) {
+ if (pinDigest[i] != entrypin[i + 1])
+ break;
+ }
+ if (i != (entrypin.length - 1)) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_BAD_PASSWORD", uid));
+ throw new EInvalidCredentials(CMS.getUserMessage("CMS_AUTHENTICATION_INVALID_CREDENTIAL"));
+ }
+
+ // pin ok. remove pin if so configured
+ // Note that this means that a policy may reject this request later,
+ // but the user will not be able to enroll again as his pin is gone.
+
+ // We remove the pin using a different connection which is bound as
+ // a more privileged user.
+
+ if (mRemovePin) {
+
+ try {
+ removePinLdapConnection.modify(userdn,
+ new LDAPModification(
+ LDAPModification.DELETE,
+ new LDAPAttribute(mPinAttr, entrypin)));
+
+ } catch (LDAPException e) {
+ log(ILogger.LL_SECURITY, CMS.getLogMessage("CMS_AUTH_CANT_REMOVE_PIN", userdn));
+ }
+
+ }
+ }
+
+ /**
+ * Returns a list of configuration parameter names.
+ * The list is passed to the configuration console so instances of
+ * this implementation can be configured through the console.
+ *
+ * @return String array of configuration parameter names.
+ */
+ public String[] getConfigParams() {
+ return (mConfigParams);
+ }
+
+ /**
+ * Returns array of required credentials for this authentication manager.
+ * @return Array of required credentials.
+ */
+ public String[] getRequiredCreds() {
+ return mRequiredCreds;
+ }
+
+ // Profile-related methods
+
+ public void init(IProfile profile, IConfigStore config)
+ throws EProfileException {
+ }
+
+ /**
+ * Retrieves the localizable name of this policy.
+ */
+ public String getName(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID_PIN_NAME");
+ }
+
+ /**
+ * Retrieves the localizable description of this policy.
+ */
+ public String getText(Locale locale) {
+ return CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID_PIN_TEXT");
+ }
+
+ /**
+ * Retrieves a list of names of the value parameter.
+ */
+ public Enumeration getValueNames() {
+ Vector v = new Vector();
+
+ v.addElement(CRED_UID);
+ v.addElement(CRED_PWD);
+ v.addElement(CRED_PIN);
+ return v.elements();
+ }
+
+ public boolean isValueWriteable(String name) {
+ if (name.equals(CRED_UID)) {
+ return true;
+ } else if (name.equals(CRED_PWD)) {
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Retrieves the descriptor of the given value
+ * parameter by name.
+ */
+ public IDescriptor getValueDescriptor(Locale locale, String name) {
+ if (name.equals(CRED_UID)) {
+ return new Descriptor(IDescriptor.STRING, null, null,
+ CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_UID"));
+ } else if (name.equals(CRED_PWD)) {
+ return new Descriptor(IDescriptor.PASSWORD, null, null,
+ CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_PWD"));
+ } else if (name.equals(CRED_PIN)) {
+ return new Descriptor(IDescriptor.PASSWORD, null, null,
+ CMS.getUserMessage(locale, "CMS_AUTHENTICATION_LDAP_PIN"));
+
+ }
+ return null;
+ }
+
+ public void populate(IAuthToken token, IRequest request)
+ throws EProfileException {
+ request.setExtData(IProfileAuthenticator.AUTHENTICATED_NAME,
+ token.getInString(USER_DN));
+ }
+
+ public boolean isSSLClientRequired() {
+ return false;
+ }
+}
+