0001: /*
0002: * (C) Copyright 2000 - 2006 Nabh Information Systems, Inc.
0003: *
0004: * This program is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU General Public License
0006: * as published by the Free Software Foundation; either version 2
0007: * of the License, or (at your option) any later version.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0017: *
0018: */
0019: package com.nabhinc.portal.spi.impl.ldap;
0020:
0021: import java.rmi.RemoteException;
0022: import java.sql.Types;
0023: import java.text.MessageFormat;
0024: import java.text.SimpleDateFormat;
0025: import java.util.ArrayList;
0026: import java.util.Date;
0027: import java.util.HashMap;
0028: import java.util.Hashtable;
0029: import java.util.List;
0030: import java.util.Map;
0031: import java.util.Vector;
0032:
0033: import com.nabhinc.portal.spi.BaseUserServiceImpl;
0034: import com.nabhinc.spi.EntityExistsException;
0035: import com.nabhinc.spi.MissingRequiredAttributeException;
0036: import com.nabhinc.spi.NoSuchEntityException;
0037: import com.nabhinc.spi.User;
0038: import com.nabhinc.spi.UserAdminService;
0039: import com.nabhinc.spi.UserImpl;
0040: import com.nabhinc.util.StringUtil;
0041: import com.nabhinc.util.db.DBConfigUtil;
0042: import com.nabhinc.ws.core.WebServiceException;
0043: import com.nabhinc.ws.server.ServerObjectConfig;
0044:
0045: import javax.naming.CommunicationException;
0046: import javax.naming.Context;
0047: import javax.naming.NameNotFoundException;
0048: import javax.naming.NamingException;
0049: import javax.naming.directory.Attribute;
0050: import javax.naming.directory.Attributes;
0051: import javax.naming.directory.DirContext;
0052: import javax.naming.directory.InitialDirContext;
0053:
0054: /**
0055: * <p>User Admin service that works with a directory
0056: * server accessed via the Java Naming and Directory Interface (JNDI) APIs.
0057: * The following constraints are imposed on the data structure in the
0058: * underlying directory server:</p>
0059: * <ul>
0060: *
0061: * <li></li>
0062: * </ul>
0063: *
0064: *
0065: *
0066: */
0067: public class UserAdminServiceLDAPImpl extends BaseUserServiceImpl
0068: implements UserAdminService {
0069:
0070: /**
0071: * JSR 168 compliant names of user info attributes supported.
0072: */
0073: private String[] uasiUserInfoAttributes = null;
0074:
0075: /**
0076: * data types for the UserInfo Attributes
0077: */
0078: private int[] uasiUserInfoAttributeTypes = null;
0079:
0080: /**
0081: * LDAP mapped fields in the directory.
0082: */
0083: private String[] uasiUserInfoAttributesLDAP = null;
0084:
0085: // ----------------------------------------------------- Instance Variables
0086:
0087: /**
0088: * Caches server context and sets object properties.
0089: */
0090: public void init(ServerObjectConfig config)
0091: throws WebServiceException {
0092: super .init(config);
0093: if (uasiUserInfoAttributes == null) {
0094: uasiUserInfoAttributes = new String[] { "user.id",
0095: "user.name.given", "user.name.family",
0096: "user.business-info.online.email",
0097: "user.business-info.telecom.telephone.number" };
0098: }
0099: if (uasiUserInfoAttributesLDAP == null) {
0100: uasiUserInfoAttributesLDAP = new String[] {
0101: "employeeNumber", "displayName", "sn", "mail",
0102: "homePhone" };
0103: }
0104: if (uasiUserInfoAttributes.length != uasiUserInfoAttributesLDAP.length) {
0105: throw new WebServiceException(
0106: "Number of user info attributes must be equal to the number of LDAP fields.");
0107: }
0108:
0109: if (uasiUserInfoAttributeTypes == null) {
0110: uasiUserInfoAttributeTypes = new int[uasiUserInfoAttributes.length];
0111: for (int i = 0; i < uasiUserInfoAttributes.length; i++) {
0112: if (uasiUserInfoAttributes[i].equals("user.id")) {
0113: uasiUserInfoAttributeTypes[i] = Types.INTEGER;
0114: } else {
0115: uasiUserInfoAttributeTypes[i] = Types.VARCHAR;
0116: }
0117: }
0118: } else {
0119: if (uasiUserInfoAttributes.length != uasiUserInfoAttributeTypes.length) {
0120: throw new WebServiceException(
0121: "Number of user attributes must be equal to the number of attrib types.");
0122: }
0123: }
0124: }
0125:
0126: public String getUserInfoAttributes() {
0127: return StringUtil.join(uasiUserInfoAttributes, ",");
0128: }
0129:
0130: public void setUserInfoAttributes(String uInfoAttribs) {
0131: Vector attribList = new Vector();
0132: String[] attribs = StringUtil.split(uInfoAttribs, ",");
0133: for (int i = 0; i < attribs.length; i++) {
0134: if (attribs[i] != null) {
0135: String attrib = attribs[i].trim();
0136: if (attrib.length() > 0)
0137: attribList.add(attrib);
0138: }
0139: }
0140: uasiUserInfoAttributes = new String[attribList.size()];
0141: attribList.copyInto(uasiUserInfoAttributes);
0142: }
0143:
0144: public String getUserInfoAttributesLDAP() {
0145: return StringUtil.join(uasiUserInfoAttributesLDAP, ",");
0146: }
0147:
0148: public void setUserInfoAttributesLDAP(String uInfoAttribsLDAP) {
0149: Vector attribList = new Vector();
0150: String[] attribs = StringUtil.split(uInfoAttribsLDAP, ",");
0151: for (int i = 0; i < attribs.length; i++) {
0152: if (attribs[i] != null) {
0153: String attrib = attribs[i].trim();
0154: if (attrib.length() > 0)
0155: attribList.add(attrib);
0156: }
0157: }
0158: uasiUserInfoAttributesLDAP = new String[attribList.size()];
0159: attribList.copyInto(uasiUserInfoAttributesLDAP);
0160: }
0161:
0162: public void setUserInfoAttributeTypes(String attribTypes) {
0163: String[] attribTypeArray = StringUtil.split(attribTypes, ",");
0164: uasiUserInfoAttributeTypes = new int[attribTypeArray.length];
0165: for (int i = 0; i < attribTypeArray.length; i++) {
0166: uasiUserInfoAttributeTypes[i] = DBConfigUtil
0167: .getSQLType(attribTypeArray[i]);
0168: }
0169: }
0170:
0171: /**
0172: * The type of authentication to use
0173: */
0174: protected String authentication = null;
0175:
0176: /**
0177: * The connection username for the server we will contact.
0178: */
0179: protected String connectionName = null;
0180:
0181: /**
0182: * The connection password for the server we will contact.
0183: */
0184: protected String connectionPassword = null;
0185:
0186: /**
0187: * The connection URL for the server we will contact.
0188: */
0189: protected String connectionURL = null;
0190:
0191: /**
0192: * The directory context linking us to our directory server.
0193: */
0194: protected DirContext context = null;
0195:
0196: /**
0197: * The JNDI context factory used to acquire our InitialContext. By
0198: * default, assumes use of an LDAP server using the standard JNDI LDAP
0199: * provider.
0200: */
0201: protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
0202:
0203: /**
0204: * The attribute names.
0205: */
0206: protected String UserInfoAttributes = null;
0207: protected String UserInfoAttributesLDAP = null;
0208:
0209: // protected String userSince = null;
0210: // protected String userLastLogin = null;
0211:
0212: /**
0213: * A string of LDAP user patterns or paths, ":"-separated
0214: * These will be used to form the distinguished name of a
0215: * user, with "{0}" marking the spot where the specified username
0216: * goes.
0217: * This is similar to userPattern, but allows for multiple searches
0218: * for a user.
0219: */
0220: protected String[] userPatternArray = null;
0221:
0222: /**
0223: * The message format used to form the distinguished name of a
0224: * user, with "{0}" marking the spot where the specified username
0225: * goes.
0226: */
0227: protected String userPattern = null;
0228:
0229: /**
0230: * An array of MessageFormat objects associated with the current
0231: * <code>userPatternArray</code>.
0232: */
0233: protected MessageFormat[] userPatternFormatArray = null;
0234:
0235: /**
0236: * How aliases should be dereferenced during search operations.
0237: */
0238: protected String derefAliases = null;
0239:
0240: /**
0241: * Constant that holds the name of the environment property for specifying
0242: * the manner in which aliases should be dereferenced.
0243: */
0244: public final static String DEREF_ALIASES = "java.naming.ldap.derefAliases";
0245:
0246: /**
0247: * Descriptive information about this Realm implementation.
0248: */
0249: protected static final String name = "JNDIRealm";
0250:
0251: /**
0252: * The protocol that will be used in the communication with the
0253: * directory server.
0254: */
0255: protected String protocol = null;
0256:
0257: /**
0258: * How should we handle referrals? Microsoft Active Directory can't handle
0259: * the default case, so an application authenticating against AD must
0260: * set referrals to "follow".
0261: */
0262: protected String referrals = null;
0263:
0264: /**
0265: * The base element for user searches.
0266: */
0267: protected String userBase = "";
0268:
0269: /**
0270: * The message format used to search for a user, with "{0}" marking
0271: * the spot where the username goes.
0272: */
0273: protected String userSearch = null;
0274:
0275: /**
0276: * The MessageFormat object associated with the current
0277: * <code>userSearch</code>.
0278: */
0279: protected MessageFormat userSearchFormat = null;
0280:
0281: /**
0282: * Should we search the entire subtree for matching users?
0283: */
0284: protected boolean userSubtree = false;
0285:
0286: /**
0287: * An alternate URL, to which, we should connect if connectionURL fails.
0288: */
0289: protected String alternateURL;
0290:
0291: /**
0292: * The number of connection attempts. If greater than zero we use the
0293: * alternate url.
0294: */
0295: protected int connectionAttempt = 0;
0296:
0297: /**
0298: * The current user pattern to be used for lookup and binding of a user.
0299: */
0300: protected int curUserPattern = 0;
0301:
0302: /**
0303: * Return the type of authentication to use.
0304: */
0305: public String getAuthentication() {
0306:
0307: return authentication;
0308:
0309: }
0310:
0311: /**
0312: * Set the type of authentication to use.
0313: *
0314: * @param authentication The authentication
0315: */
0316: public void setAuthentication(String authentication) {
0317:
0318: this .authentication = authentication;
0319:
0320: }
0321:
0322: /**
0323: * Return the connection username for this Realm.
0324: */
0325: public String getConnectionName() {
0326:
0327: return (this .connectionName);
0328:
0329: }
0330:
0331: /**
0332: * Set the connection username for this Realm.
0333: *
0334: * @param connectionName The new connection username
0335: */
0336: public void setConnectionName(String connectionName) {
0337:
0338: this .connectionName = connectionName;
0339:
0340: }
0341:
0342: /**
0343: * Return the connection password for this Realm.
0344: */
0345: public String getConnectionPassword() {
0346:
0347: return (this .connectionPassword);
0348:
0349: }
0350:
0351: /**
0352: * Set the connection password for this Realm.
0353: *
0354: * @param connectionPassword The new connection password
0355: */
0356: public void setConnectionPassword(String connectionPassword) {
0357:
0358: this .connectionPassword = connectionPassword;
0359:
0360: }
0361:
0362: /**
0363: * Return the connection URL for this Realm.
0364: */
0365: public String getConnectionURL() {
0366:
0367: return (this .connectionURL);
0368:
0369: }
0370:
0371: /**
0372: * Set the connection URL for this Realm.
0373: *
0374: * @param connectionURL The new connection URL
0375: */
0376: public void setConnectionURL(String connectionURL) {
0377:
0378: this .connectionURL = connectionURL;
0379:
0380: }
0381:
0382: /**
0383: * Return the JNDI context factory for this Realm.
0384: */
0385: public String getContextFactory() {
0386:
0387: return (this .contextFactory);
0388:
0389: }
0390:
0391: /**
0392: * Set the JNDI context factory for this Realm.
0393: *
0394: * @param contextFactory The new context factory
0395: */
0396: public void setContextFactory(String contextFactory) {
0397:
0398: this .contextFactory = contextFactory;
0399:
0400: }
0401:
0402: /**
0403: * Return the derefAliases setting to be used.
0404: */
0405: public java.lang.String getDerefAliases() {
0406: return derefAliases;
0407: }
0408:
0409: /**
0410: * Set the value for derefAliases to be used when searching the directory.
0411: *
0412: * @param derefAliases New value of property derefAliases.
0413: */
0414: public void setDerefAliases(java.lang.String derefAliases) {
0415: this .derefAliases = derefAliases;
0416: }
0417:
0418: /**
0419: * Return the protocol to be used.
0420: */
0421: public String getProtocol() {
0422:
0423: return protocol;
0424:
0425: }
0426:
0427: /**
0428: * Set the protocol for this Realm.
0429: *
0430: * @param protocol The new protocol.
0431: */
0432: public void setProtocol(String protocol) {
0433:
0434: this .protocol = protocol;
0435:
0436: }
0437:
0438: /**
0439: * Returns the current settings for handling JNDI referrals.
0440: */
0441: public String getReferrals() {
0442: return referrals;
0443: }
0444:
0445: /**
0446: * How do we handle JNDI referrals? ignore, follow, or throw
0447: * (see javax.naming.Context.REFERRAL for more information).
0448: */
0449: public void setReferrals(String referrals) {
0450: this .referrals = referrals;
0451: }
0452:
0453: /**
0454: * Return the base element for user searches.
0455: */
0456: public String getUserBase() {
0457:
0458: return (this .userBase);
0459:
0460: }
0461:
0462: /**
0463: * Set the base element for user searches.
0464: *
0465: * @param userBase The new base element
0466: */
0467: public void setUserBase(String userBase) {
0468:
0469: this .userBase = userBase;
0470:
0471: }
0472:
0473: /**
0474: * Return the message format pattern for selecting users in this Realm.
0475: */
0476: public String getUserSearch() {
0477:
0478: return (this .userSearch);
0479:
0480: }
0481:
0482: /**
0483: * Set the message format pattern for selecting users in this Realm.
0484: *
0485: * @param userSearch The new user search pattern
0486: */
0487: public void setUserSearch(String userSearch) {
0488:
0489: this .userSearch = userSearch;
0490: if (userSearch == null)
0491: userSearchFormat = null;
0492: else
0493: userSearchFormat = new MessageFormat(userSearch);
0494:
0495: }
0496:
0497: /**
0498: * Return the "search subtree for users" flag.
0499: */
0500: public boolean getUserSubtree() {
0501:
0502: return (this .userSubtree);
0503:
0504: }
0505:
0506: /**
0507: * Set the "search subtree for users" flag.
0508: *
0509: * @param userSubtree The new search flag
0510: */
0511: public void setUserSubtree(boolean userSubtree) {
0512:
0513: this .userSubtree = userSubtree;
0514:
0515: }
0516:
0517: /**
0518: * Return the message format pattern for selecting users in this Realm.
0519: */
0520: public String getUserPattern() {
0521:
0522: return (this .userPattern);
0523:
0524: }
0525:
0526: /**
0527: * Set the message format pattern for selecting users in this Realm.
0528: * This may be one simple pattern, or multiple patterns to be tried,
0529: * separated by parentheses. (for example, either "cn={0}", or
0530: * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported,
0531: * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is
0532: * also valid. Complex search strings with &, etc are NOT supported.
0533: *
0534: * @param userPattern The new user pattern
0535: */
0536: public void setUserPattern(String userPattern) {
0537:
0538: this .userPattern = userPattern;
0539: if (userPattern == null)
0540: userPatternArray = null;
0541: else {
0542: userPatternArray = parseUserPatternString(userPattern);
0543: int len = this .userPatternArray.length;
0544: userPatternFormatArray = new MessageFormat[len];
0545: for (int i = 0; i < len; i++) {
0546: userPatternFormatArray[i] = new MessageFormat(
0547: userPatternArray[i]);
0548: }
0549: }
0550: }
0551:
0552: /**
0553: * Getter for property alternateURL.
0554: *
0555: * @return Value of property alternateURL.
0556: */
0557: public String getAlternateURL() {
0558:
0559: return this .alternateURL;
0560:
0561: }
0562:
0563: /**
0564: * Setter for property alternateURL.
0565: *
0566: * @param alternateURL New value of property alternateURL.
0567: */
0568: public void setAlternateURL(String alternateURL) {
0569:
0570: this .alternateURL = alternateURL;
0571:
0572: }
0573:
0574: // ========================================
0575:
0576: public int getUserCount() throws RemoteException {
0577: // TODO Auto-generated method stub
0578: return 0;
0579: }
0580:
0581: public User getUser(int userID) throws NoSuchEntityException,
0582: RemoteException {
0583: // TODO Auto-generated method stub
0584:
0585: return (getUser("sbuser"));
0586: }
0587:
0588: public User getUser(String userName) throws NoSuchEntityException,
0589: RemoteException {
0590:
0591: User user = new UserImpl();
0592: DirContext context = null;
0593: Attributes attrs = null;
0594:
0595: try {
0596:
0597: // Ensure that we have a directory context available
0598: context = open();
0599:
0600: // Occassionally the directory context will timeout. Try one more
0601: // time before giving up.
0602: try {
0603:
0604: attrs = getUserAttributes(context, userName);
0605:
0606: } catch (CommunicationException e) {
0607:
0608: // log the exception so we know it's there.
0609: warn("Communication exception.", e);
0610:
0611: // close the connection so we know it will be reopened.
0612: if (context != null)
0613: close(context);
0614:
0615: // open a new directory context.
0616: context = open();
0617:
0618: // Try the authentication again.
0619: attrs = getUserAttributes(context, userName);
0620:
0621: }
0622:
0623: user = createUser(attrs);
0624:
0625: // Release this context
0626: release(context);
0627:
0628: return (user);
0629:
0630: } catch (NamingException e) {
0631:
0632: // Log the problem for posterity
0633: error("naming exception", e);
0634:
0635: // Close the connection so that it gets reopened next time
0636: if (context != null)
0637: close(context);
0638:
0639: // Return "not authenticated" for this request
0640: throw new RemoteException("Could not look up dir context.",
0641: e);
0642:
0643: }
0644: }
0645:
0646: public void updateLastLogin(String userName) throws RemoteException {
0647: // TODO Auto-generated method stub
0648:
0649: }
0650:
0651: public void setPassword(String userName, String password)
0652: throws RemoteException {
0653: // TODO Auto-generated method stub
0654:
0655: }
0656:
0657: public void deleteUsers(int[] userID) throws RemoteException {
0658: // TODO Auto-generated method stub
0659:
0660: }
0661:
0662: public void deleteUsers(String[] usernames) throws RemoteException {
0663: // TODO Auto-generated method stub
0664:
0665: }
0666:
0667: public Map getUserInfo(String userName) throws RemoteException,
0668: NoSuchEntityException {
0669:
0670: DirContext context = null;
0671: Map userInfo = new HashMap();
0672: Attributes attrs = null;
0673:
0674: try {
0675:
0676: // Ensure that we have a directory context available
0677: context = open();
0678:
0679: // Occassionally the directory context will timeout. Try one more
0680: // time before giving up.
0681: try {
0682:
0683: attrs = getUserAttributes(context, userName);
0684:
0685: } catch (CommunicationException e) {
0686:
0687: // log the exception so we know it's there.
0688: warn("Communication exception.", e);
0689:
0690: // close the connection so we know it will be reopened.
0691: if (context != null)
0692: close(context);
0693:
0694: // open a new directory context.
0695: context = open();
0696:
0697: // Try the authentication again.
0698: attrs = getUserAttributes(context, userName);
0699:
0700: }
0701:
0702: userInfo = getUserInfo(attrs);
0703:
0704: // Release this context
0705: release(context);
0706:
0707: return (userInfo);
0708:
0709: } catch (NamingException e) {
0710:
0711: // Log the problem for posterity
0712: error("naming exception", e);
0713:
0714: // Close the connection so that it gets reopened next time
0715: if (context != null)
0716: close(context);
0717:
0718: // Return "not authenticated" for this request
0719: throw new RemoteException("Could not look up dir context.",
0720: e);
0721:
0722: }
0723:
0724: }
0725:
0726: /**
0727: * Return the attributes associated with the given user name.
0728: */
0729: protected synchronized Attributes getUserAttributes(
0730: DirContext context, String userName) throws NamingException {
0731:
0732: // Get attributes to retrieve from user entry
0733: ArrayList list = new ArrayList();
0734:
0735: list = updateAttrList();
0736:
0737: // Form the dn from the user pattern
0738: String dn = userPatternFormatArray[curUserPattern]
0739: .format(new String[] { userName });
0740:
0741: // Get required attributes from user entry
0742: Attributes attrs = null;
0743: String[] attrIds = new String[list.size()];
0744: list.toArray(attrIds);
0745:
0746: try {
0747: attrs = context.getAttributes(dn, attrIds);
0748: } catch (NameNotFoundException e) {
0749: return (null);
0750: }
0751: if (attrs == null)
0752: return (null);
0753:
0754: return (attrs);
0755: }
0756:
0757: private Map getUserInfo(Attributes attrs) throws NamingException {
0758: Map usr = new HashMap();
0759: String sVal = null;
0760: SimpleDateFormat dtFormat = new SimpleDateFormat();
0761: for (int i = 0; i < uasiUserInfoAttributes.length; i++) {
0762: sVal = getAttributeValue(uasiUserInfoAttributesLDAP[i],
0763: attrs);
0764: usr.put(uasiUserInfoAttributes[i], sVal);
0765: /*
0766: switch (uasiUserInfoAttributeTypes[i]) {
0767: case Types.INTEGER:
0768: usr.put (uasiUserInfoAttributes[i], Integer.valueOf(sVal));
0769: break;
0770: case Types.BOOLEAN:
0771: if (sVal.equalsIgnoreCase("true") || sVal.equalsIgnoreCase("1") || sVal.equalsIgnoreCase("yes") || sVal.equalsIgnoreCase("on")) {
0772: usr.put (uasiUserInfoAttributes[i], Boolean.TRUE);
0773: } else {
0774: usr.put (uasiUserInfoAttributes[i], Boolean.FALSE);
0775: }
0776: case Types.DATE:
0777: try {
0778: usr.put(uasiUserInfoAttributes[i], dtFormat.parse(sVal));
0779: } catch (Exception e) {
0780: usr.put(uasiUserInfoAttributes[i], null);
0781: e.printStackTrace();
0782: }
0783: break;
0784: default: // case Types.VARCHAR: treat default string
0785: usr.put (uasiUserInfoAttributes[i], sVal);
0786: break;
0787: }
0788: */
0789: }
0790: return (usr);
0791: }
0792:
0793: /**
0794: * Return a String representing the value of the specified attribute.
0795: *
0796: * @param attrId Attribute name
0797: * @param attrs Attributes containing the required value
0798: *
0799: * @exception NamingException if a directory server error occurs
0800: */
0801: private String getAttributeValue(String attrId, Attributes attrs)
0802: throws NamingException {
0803:
0804: if (isTraceEnabled())
0805: trace(" retrieving attribute " + attrId);
0806:
0807: if (attrId == null || attrs == null)
0808: return null;
0809:
0810: Attribute attr = attrs.get(attrId);
0811: if (attr == null)
0812: return (null);
0813: Object value = attr.get();
0814: if (value == null)
0815: return (null);
0816: String valueString = null;
0817: if (value instanceof byte[])
0818: valueString = new String((byte[]) value);
0819: else
0820: valueString = value.toString();
0821:
0822: return valueString;
0823: }
0824:
0825: /**
0826: * Open (if necessary) and return a connection to the configured
0827: * directory server for this Realm.
0828: *
0829: * @exception NamingException if a directory server error occurs
0830: */
0831: protected DirContext open() throws NamingException {
0832:
0833: // Do nothing if there is a directory server connection already open
0834: if (context != null)
0835: return (context);
0836:
0837: try {
0838:
0839: // Ensure that we have a directory context available
0840: context = new InitialDirContext(
0841: getDirectoryContextEnvironment());
0842:
0843: } catch (Exception e) {
0844:
0845: connectionAttempt = 1;
0846:
0847: // log the first exception.
0848: warn("jndi auth exception", e);
0849:
0850: // Try connecting to the alternate url.
0851: context = new InitialDirContext(
0852: getDirectoryContextEnvironment());
0853:
0854: } finally {
0855:
0856: // reset it in case the connection times out.
0857: // the primary may come back.
0858: connectionAttempt = 0;
0859:
0860: }
0861:
0862: return (context);
0863:
0864: }
0865:
0866: /**
0867: * Close any open connection to the directory server for this Realm.
0868: *
0869: * @param context The directory context to be closed
0870: */
0871: protected void close(DirContext context) {
0872:
0873: // Do nothing if there is no opened connection
0874: if (context == null)
0875: return;
0876:
0877: // Close our opened connection
0878: try {
0879: if (isDebugEnabled())
0880: debug("Closing directory context");
0881: context.close();
0882: } catch (NamingException e) {
0883: error("jndiRealm.close", e);
0884: }
0885: this .context = null;
0886:
0887: }
0888:
0889: /**
0890: * Create our directory context configuration.
0891: *
0892: * @return java.util.Hashtable the configuration for the directory context.
0893: */
0894: protected Hashtable getDirectoryContextEnvironment() {
0895:
0896: Hashtable env = new Hashtable();
0897:
0898: // Configure our directory context environment.
0899: if (connectionAttempt == 0)
0900: debug("Connecting to URL " + connectionURL);
0901: else if (connectionAttempt > 0)
0902: debug("Connecting to URL " + alternateURL);
0903: env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
0904: if (connectionName != null)
0905: env.put(Context.SECURITY_PRINCIPAL, connectionName);
0906: if (connectionPassword != null)
0907: env.put(Context.SECURITY_CREDENTIALS, connectionPassword);
0908: if (connectionURL != null && connectionAttempt == 0)
0909: env.put(Context.PROVIDER_URL, connectionURL);
0910: else if (alternateURL != null && connectionAttempt > 0)
0911: env.put(Context.PROVIDER_URL, alternateURL);
0912: if (authentication != null)
0913: env.put(Context.SECURITY_AUTHENTICATION, authentication);
0914: if (protocol != null)
0915: env.put(Context.SECURITY_PROTOCOL, protocol);
0916: if (referrals != null)
0917: env.put(Context.REFERRAL, referrals);
0918: if (derefAliases != null)
0919: env.put(DEREF_ALIASES, derefAliases);
0920:
0921: return env;
0922:
0923: }
0924:
0925: /**
0926: * Release our use of this connection so that it can be recycled.
0927: *
0928: * @param context The directory context to release
0929: */
0930: protected void release(DirContext context) {
0931:
0932: ; // NO-OP since we are not pooling anything
0933:
0934: }
0935:
0936: public List getUsers(int offset, int maxUsers, String orderby,
0937: boolean isDescending) throws RemoteException {
0938: // TODO Auto-generated method stub
0939: return null;
0940: }
0941:
0942: public String getUserNameFromEmail(String email)
0943: throws NoSuchEntityException, RemoteException {
0944: // TODO Auto-generated method stub
0945: return null;
0946: }
0947:
0948: public void setIcon(String userName, byte[] icon)
0949: throws RemoteException {
0950: // TODO Auto-generated method stub
0951:
0952: }
0953:
0954: public byte[] getIcon(String userName) throws RemoteException {
0955: // TODO Auto-generated method stub
0956: return null;
0957: }
0958:
0959: public void createUser(User usr, String password, int[] roleIDs)
0960: throws EntityExistsException,
0961: MissingRequiredAttributeException, RemoteException {
0962: // TODO Auto-generated method stub
0963:
0964: }
0965:
0966: public void updateUser(User usr, int[] roleIDs)
0967: throws EntityExistsException,
0968: MissingRequiredAttributeException, RemoteException {
0969: // TODO Auto-generated method stub
0970:
0971: }
0972:
0973: public void updateUserProfile(User usr)
0974: throws EntityExistsException, RemoteException {
0975: // TODO Auto-generated method stub
0976:
0977: }
0978:
0979: /**
0980: * Given a string containing LDAP patterns for user locations (separated by
0981: * parentheses in a pseudo-LDAP search string format -
0982: * "(location1)(location2)", returns an array of those paths. Real LDAP
0983: * search strings are supported as well (though only the "|" "OR" type).
0984: *
0985: * @param userPatternString - a string LDAP search paths surrounded by
0986: * parentheses
0987: */
0988: protected String[] parseUserPatternString(String userPatternString) {
0989:
0990: if (userPatternString != null) {
0991: ArrayList pathList = new ArrayList();
0992: int startParenLoc = userPatternString.indexOf('(');
0993: if (startParenLoc == -1) {
0994: // no parens here; return whole thing
0995: return new String[] { userPatternString };
0996: }
0997: int startingPoint = 0;
0998: while (startParenLoc > -1) {
0999: int endParenLoc = 0;
1000: // weed out escaped open parens and parens enclosing the
1001: // whole statement (in the case of valid LDAP search
1002: // strings: (|(something)(somethingelse))
1003: while ((userPatternString.charAt(startParenLoc + 1) == '|')
1004: || (startParenLoc != 0 && userPatternString
1005: .charAt(startParenLoc - 1) == '\\')) {
1006: startParenLoc = userPatternString.indexOf("(",
1007: startParenLoc + 1);
1008: }
1009: endParenLoc = userPatternString.indexOf(")",
1010: startParenLoc + 1);
1011: // weed out escaped end-parens
1012: while (userPatternString.charAt(endParenLoc - 1) == '\\') {
1013: endParenLoc = userPatternString.indexOf(")",
1014: endParenLoc + 1);
1015: }
1016: String nextPathPart = userPatternString.substring(
1017: startParenLoc + 1, endParenLoc);
1018: pathList.add(nextPathPart);
1019: startingPoint = endParenLoc + 1;
1020: startParenLoc = userPatternString.indexOf('(',
1021: startingPoint);
1022: }
1023: return (String[]) pathList.toArray(new String[] {});
1024: }
1025: return null;
1026:
1027: }
1028:
1029: /**
1030: * Given an LDAP search string, returns the string with certain characters
1031: * escaped according to RFC 2254 guidelines.
1032: * The character mapping is as follows:
1033: * char -> Replacement
1034: * ---------------------------
1035: * * -> \2a
1036: * ( -> \28
1037: * ) -> \29
1038: * \ -> \5c
1039: * \0 -> \00
1040: * @param inString string to escape according to RFC 2254 guidelines
1041: * @return String the escaped/encoded result
1042: */
1043: protected String doRFC2254Encoding(String inString) {
1044: StringBuffer buf = new StringBuffer(inString.length());
1045: for (int i = 0; i < inString.length(); i++) {
1046: char c = inString.charAt(i);
1047: switch (c) {
1048: case '\\':
1049: buf.append("\\5c");
1050: break;
1051: case '*':
1052: buf.append("\\2a");
1053: break;
1054: case '(':
1055: buf.append("\\28");
1056: break;
1057: case ')':
1058: buf.append("\\29");
1059: break;
1060: case '\0':
1061: buf.append("\\00");
1062: break;
1063: default:
1064: buf.append(c);
1065: break;
1066: }
1067: }
1068: return buf.toString();
1069: }
1070:
1071: private User createUser(Attributes attrs) throws NamingException {
1072: User usr = new UserImpl();
1073: // userid, username, fname, lname, oemail, joined, lastlogin, mname, suffix, address1, address2, city, state, country, zipcode, ophone, hphone, cphone, hemail, ofax, hfax, pager, website, gender, bdate, sig, aim, yim, msnm, icq, showemail, showname FROM SB_USERS";
1074:
1075: Map UserInfo = getUserInfo(attrs);
1076:
1077: if (UserInfo.containsKey("user.id")
1078: && UserInfo.get("user.id") != null) {
1079: usr.setId(Integer.parseInt(UserInfo.get("user.id")
1080: .toString()));
1081: } else {
1082: usr.setId(1); // Set a default user_id for LDAP authentication
1083: }
1084:
1085: if (UserInfo.containsKey("user.id")
1086: && UserInfo.get("user.id") != null)
1087: usr.setId(Integer.parseInt(UserInfo.get("user.id")
1088: .toString()));
1089:
1090: if (UserInfo.containsKey("user.name.given")
1091: && UserInfo.get("user.name.given") != null)
1092: usr.setUserName(UserInfo.get("user.name.given").toString());
1093:
1094: if (UserInfo.containsKey("user.name.family")
1095: && UserInfo.get("user.name.family") != null)
1096: usr
1097: .setLastName(UserInfo.get("user.name.family")
1098: .toString());
1099:
1100: if (UserInfo.containsKey("user.business-info.online.email")
1101: && UserInfo.get("user.business-info.online.email") != null)
1102: usr.setPrimaryEmail(UserInfo.get(
1103: "user.business-info.online.email").toString());
1104:
1105: //usr.setId(Integer.parseInt(getAttributeValue(userID, attrs)));
1106: //usr.setUserName(getAttributeValue(userDisplayName, attrs));
1107: //usr.setFirstName(getAttributeValue(userFirstName, attrs));
1108: //usr.setLastName(getAttributeValue(userLastName, attrs));
1109: //usr.setPrimaryEmail(getAttributeValue(userPrimaryEmail, attrs));
1110: //usr.setPrimaryEmail(getAttributeValue(userTelephone, attrs));
1111: // usr.setUserSince(getAttributeValue(userSince, attrs));
1112: // usr.setDisabled(results.getBoolean(7));
1113: // usr.setLastLogin(getAttributeValue(userLastLogin, attrs));
1114:
1115: /*
1116: for (int j=0; j<uasiStringUserAttributes.length; j++) {
1117: String attrValue = results.getString(uasiStringUserAttributes[j]);
1118: if (attrValue != null) usr.getProfile().put(uasiStringUserAttributes[j], attrValue);
1119: }
1120:
1121: for (int j=0; j<uasiBooleanUserAttributes.length; j++) {
1122: boolean attrValue = results.getBoolean(uasiBooleanUserAttributes[j]);
1123: if (attrValue) usr.getProfile().put(uasiBooleanUserAttributes[j], Boolean.TRUE);
1124: }
1125:
1126: for (int j=0; j<uasiIntUserAttributes.length; j++) {
1127: int attrValue = results.getInt(uasiIntUserAttributes[j]);
1128: if (attrValue != 0)
1129: usr.getProfile().put(uasiIntUserAttributes[j], new Integer(attrValue));
1130: }
1131:
1132: for (int j=0; j<uasiDateUserAttributes.length; j++) {
1133: Date attrValue = results.getDate(uasiDateUserAttributes[j]);
1134: if (attrValue != null)
1135: usr.getProfile().put(uasiDateUserAttributes[j], attrValue);
1136: }
1137: */
1138:
1139: return usr;
1140: }
1141:
1142: private ArrayList updateAttrList() {
1143: ArrayList list = new ArrayList();
1144:
1145: for (int i = 0; i < uasiUserInfoAttributesLDAP.length; i++) {
1146: list.add(uasiUserInfoAttributesLDAP[i]);
1147: }
1148: return (list);
1149: }
1150:
1151: }
|