From a4682ceae6774956461edd03b2485bbacea445f4 Mon Sep 17 00:00:00 2001 From: mharmsen Date: Tue, 4 Oct 2011 01:17:41 +0000 Subject: Bugzilla Bug #688225 - (dogtagIPAv2.1) TRACKER: of the Dogtag fixes for freeIPA 2.1 git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/tags/IPA_v2_RHEL_6_2_20111003@2252 c9f7a03b-bd48-0410-a16d-cbbf54688b0b --- .../netscape/cms/authentication/AVAPattern.java | 542 ++++++++++ .../authentication/AgentCertAuthentication.java | 325 ++++++ .../com/netscape/cms/authentication/CMCAuth.java | 1048 ++++++++++++++++++++ .../src/com/netscape/cms/authentication/Crypt.java | 437 ++++++++ .../com/netscape/cms/authentication/DNPattern.java | 211 ++++ .../cms/authentication/DirBasedAuthentication.java | 657 ++++++++++++ .../netscape/cms/authentication/FlatFileAuth.java | 678 +++++++++++++ .../netscape/cms/authentication/HashAuthData.java | 117 +++ .../cms/authentication/HashAuthentication.java | 290 ++++++ .../netscape/cms/authentication/PortalEnroll.java | 458 +++++++++ .../netscape/cms/authentication/RDNPattern.java | 227 +++++ .../SSLclientCertAuthentication.java | 353 +++++++ .../netscape/cms/authentication/SharedSecret.java | 36 + .../cms/authentication/TokenAuthentication.java | 298 ++++++ .../authentication/UdnPwdDirAuthentication.java | 199 ++++ .../authentication/UidPwdDirAuthentication.java | 270 +++++ .../authentication/UidPwdPinDirAuthentication.java | 464 +++++++++ 17 files changed, 6610 insertions(+) create mode 100644 pki/base/common/src/com/netscape/cms/authentication/AVAPattern.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/AgentCertAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/CMCAuth.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/Crypt.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/DNPattern.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/DirBasedAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/FlatFileAuth.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/HashAuthData.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/HashAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/PortalEnroll.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/RDNPattern.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/SSLclientCertAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/SharedSecret.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/TokenAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/UdnPwdDirAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/UidPwdDirAuthentication.java create mode 100644 pki/base/common/src/com/netscape/cms/authentication/UidPwdPinDirAuthentication.java (limited to 'pki/base/common/src/com/netscape/cms/authentication') 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.

+ * + * 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.

+ * + * The syntax is + *

+ *		dnPattern := rdnPattern *[ "," rdnPattern ]
+ *		rdnPattern := avaPattern *[ "+" avaPattern ]
+ * 		avaPattern := name "=" value | 
+ *				      name "=" "$attr" "." attrName [ "." attrNumber ] | 
+ *				      name "=" "$dn" "." attrName [ "." attrNumber ] | 
+ *				 	  "$dn" "." "$rdn" "." number
+ * 
+ *
+ * Example1: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US 
+ * Ldap entry: dn:  UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example2: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs + * in a RDN in this example.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ *
+ * Example3: CN=$attr.cn, $rdn.2, O=$dn.o, C=US
+ * Ldap entry: dn:  UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * followed by the second RDN in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example4: CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * 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.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ * 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. + *

+ * + * @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 + *

+ * 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 + *

+ * 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 + *

+ * + * @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. + *

+ * @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. + *

+ * + *

+ * @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. + *

+ * @return String array of configuration parameter names. + */ + public String[] getConfigParams() { + return (mConfigParams); + } + + /** + * gets the configuration substore used by this authentication + * plug-in + *

+ * @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. + *

+ * @return list of required credentials as strings. + */ + public String[] getRequiredCreds() { + return (mRequiredCreds); + } + + /** + * prepares for shutdown. + */ + public void shutdown() { + } + + ///////////////////////////////// + // IExtendedPluginInfo methods // + ///////////////////////////////// + + /** + * Activate the help system. + *

+ * @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. + *

+ * @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. + *

+ * + * @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. + *

+ * + * @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.

+ * + * 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.

+ * + * The syntax is + *

+ *		dnPattern := rdnPattern *[ "," rdnPattern ]
+ *		rdnPattern := avaPattern *[ "+" avaPattern ]
+ * 		avaPattern := name "=" value | 
+ *				      name "=" "$attr" "." attrName [ "." attrNumber ] | 
+ *				      name "=" "$dn" "." attrName [ "." attrNumber ] | 
+ *				 	  "$dn" "." "$rdn" "." number
+ * 
+ *
+ * Example1: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US 
+ * Ldap entry: dn:  UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example2: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs + * in a RDN in this example.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ *
+ * Example3: CN=$attr.cn, $rdn.2, O=$dn.o, C=US
+ * Ldap entry: dn:  UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * followed by the second RDN in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example4: CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * 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.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ * 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. + * + *

+ * @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:
+ *

+     *		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.
+     * 
+ *

+ * 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. + *

+ * The syntax is + *

+     *     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. 
+     * 
+     * 
+ *

+ * Example: + *

+     * dnpattern: 
+     *     E=$attr.mail.1, CN=$attr.cn, OU=$attr.ou.2, O=$dn.o, C=US
+     * 
+ * Ldap entry dn: + * UID=joesmith, OU=people, O=Acme.com + *
+ * Ldap attributes: + * cn: Joe Smith + * sn: Smith + * mail: joesmith@acme.com + * mail: joesmith@redhat.com + * ou: people + * ou: IS + * etc. + *
+ *

+ * The subject name formulated in the cert will be :
+ *

+     *   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"
+     * 
+ * + * @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 + *

+ * @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:

+     * param1: valuea
+     * param2: valueb
+     * -blank-line-
+     * param1: valuec
+     * param2: valued
+     * 
+ * + * @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. + *

+ * @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 + *

+ * + * @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 + *

+ * + * @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. + *

+ * @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.

+ * + * 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.

+ * + * The syntax is + *

+ *		dnPattern := rdnPattern *[ "," rdnPattern ]
+ *		rdnPattern := avaPattern *[ "+" avaPattern ]
+ * 		avaPattern := name "=" value | 
+ *				      name "=" "$attr" "." attrName [ "." attrNumber ] | 
+ *				      name "=" "$dn" "." attrName [ "." attrNumber ] | 
+ *				 	  "$dn" "." "$rdn" "." number
+ * 
+ *
+ * Example1: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US 
+ * Ldap entry: dn:  UID=jjames, OU=IS, OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example2: E=$attr.mail.1, CN=$attr.cn, OU=$dn.ou.2, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * E=jjames@acme.org, CN=Jesse James, OU=people, O=acme.org, C=US + *

+ * E = the first 'mail' ldap attribute value in user's entry.
+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * OU = the second 'ou' value in the user's entry DN. note multiple AVAs + * in a RDN in this example.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ *
+ * Example3: CN=$attr.cn, $rdn.2, O=$dn.o, C=US
+ * Ldap entry: dn:  UID=jjames, OU=IS+OU=people, O=acme.org
+ * Ldap attributes: cn: Jesse James 
+ * Ldap attributes: mail: jjames@acme.org
+ * 

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=IS+OU=people, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * followed by the second RDN in the user's entry DN.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ * Example4: CN=$attr.cn, OU=$dn.ou.2+OU=$dn.ou.1, O=$dn.o, C=US + * Ldap entry: dn: UID=jjames, OU=IS+OU=people, O=acme.org + * Ldap attributes: cn: Jesse James + * Ldap attributes: mail: jjames@acme.org + *

+ * The subject name formulated will be :
+ * CN=Jesse James, OU=people+OU=IS, O=acme.org, C=US + *

+ * CN = the (first) 'cn' ldap attribute value in the user's entry.
+ * 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.
+ * O = the (first) 'o' value in the user's entry DN.
+ * C = the string "US" + *

+ *

+ * 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 + *

+ * + */ +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 + *

+ * 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 + *

+ * 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. + *

+ * + * @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 + *

+ * 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 + *

+ * 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 + *

+ * + * @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. + *

+ * @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 + *

+ * + * @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 + *

+ * + * @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; + } +} + -- cgit