Source Code Cross Referenced for LdapClient.java in  » 6.0-JDK-Modules-com.sun » jndi » com » sun » jndi » ldap » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules com.sun » jndi » com.sun.jndi.ldap 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 1999-2005 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.jndi.ldap;
0027:
0028:        import java.net.*;
0029:        import java.io.*;
0030:        import java.util.Vector;
0031:        import java.util.Hashtable;
0032:
0033:        import javax.naming.*;
0034:        import javax.naming.directory.*;
0035:        import javax.naming.ldap.*;
0036:
0037:        import com.sun.jndi.ldap.pool.PooledConnection;
0038:        import com.sun.jndi.ldap.pool.PoolCallback;
0039:        import com.sun.jndi.ldap.sasl.LdapSasl;
0040:        import com.sun.jndi.ldap.sasl.SaslInputStream;
0041:
0042:        /**
0043:         * LDAP (RFC-1777) and LDAPv3 (RFC-2251) compliant client
0044:         *
0045:         * This class represents a connection to an LDAP client.
0046:         * Callers interact with this class at an LDAP operation level.
0047:         * That is, the caller invokes a method to do a SEARCH or MODRDN
0048:         * operation and gets back the result. 
0049:         * The caller uses the constructor to create a connection to the server.
0050:         * It then needs to use authenticate() to perform an LDAP BIND.
0051:         * Note that for v3, BIND is optional so authenticate() might not
0052:         * actually send a BIND. authenticate() can be used later on to issue
0053:         * a BIND, for example, for a v3 client that wants to change the connection's
0054:         * credentials.
0055:         *<p>
0056:         * Multiple LdapCtx might share the same LdapClient. For example, contexts
0057:         * derived from the same initial context would share the same LdapClient
0058:         * until changes to a context's properties necessitates its own LdapClient.
0059:         * LdapClient methods that access shared data are thread-safe (i.e., caller
0060:         * does not have to sync).
0061:         *<p>
0062:         * Fields:
0063:         *   isLdapv3 - no sync; initialized and updated within sync authenticate();
0064:         *       always updated when connection is "quiet" and not shared;
0065:         *       read access from outside LdapClient not sync
0066:         *   referenceCount - sync within LdapClient; exception is forceClose() which
0067:         *       is used by Connection thread to close connection upon receiving
0068:         *       an Unsolicited Notification.
0069:         *       access from outside LdapClient must sync;
0070:         *   conn - no sync; Connection takes care of its own sync
0071:         *   unsolicited - sync Vector; multiple operations sync'ed
0072:         * 
0073:         * @author Vincent Ryan
0074:         * @author Jagane Sundar
0075:         * @author Rosanna Lee
0076:         */
0077:
0078:        public final class LdapClient implements  PooledConnection {
0079:            // ---------------------- Constants ----------------------------------
0080:            private static final int debug = 0;
0081:            static final boolean caseIgnore = true;
0082:
0083:            // Default list of binary attributes
0084:            private static final Hashtable defaultBinaryAttrs = new Hashtable(
0085:                    23, 0.75f);
0086:            static {
0087:                defaultBinaryAttrs.put("userpassword", Boolean.TRUE); //2.5.4.35
0088:                defaultBinaryAttrs.put("javaserializeddata", Boolean.TRUE);
0089:                //1.3.6.1.4.1.42.2.27.4.1.8
0090:                defaultBinaryAttrs.put("javaserializedobject", Boolean.TRUE);
0091:                // 1.3.6.1.4.1.42.2.27.4.1.2
0092:                defaultBinaryAttrs.put("jpegphoto", Boolean.TRUE);
0093:                //0.9.2342.19200300.100.1.60
0094:                defaultBinaryAttrs.put("audio", Boolean.TRUE); //0.9.2342.19200300.100.1.55
0095:                defaultBinaryAttrs.put("thumbnailphoto", Boolean.TRUE);
0096:                //1.3.6.1.4.1.1466.101.120.35
0097:                defaultBinaryAttrs.put("thumbnaillogo", Boolean.TRUE);
0098:                //1.3.6.1.4.1.1466.101.120.36
0099:                defaultBinaryAttrs.put("usercertificate", Boolean.TRUE); //2.5.4.36
0100:                defaultBinaryAttrs.put("cacertificate", Boolean.TRUE); //2.5.4.37
0101:                defaultBinaryAttrs.put("certificaterevocationlist",
0102:                        Boolean.TRUE);
0103:                //2.5.4.39
0104:                defaultBinaryAttrs.put("authorityrevocationlist", Boolean.TRUE); //2.5.4.38
0105:                defaultBinaryAttrs.put("crosscertificatepair", Boolean.TRUE); //2.5.4.40
0106:                defaultBinaryAttrs.put("photo", Boolean.TRUE); //0.9.2342.19200300.100.1.7
0107:                defaultBinaryAttrs.put("personalsignature", Boolean.TRUE);
0108:                //0.9.2342.19200300.100.1.53
0109:                defaultBinaryAttrs.put("x500uniqueidentifier", Boolean.TRUE); //2.5.4.45
0110:            }
0111:
0112:            private static final String DISCONNECT_OID = "1.3.6.1.4.1.1466.20036";
0113:
0114:            // ----------------------- instance fields ------------------------
0115:            boolean isLdapv3; // Used by LdapCtx 
0116:            int referenceCount = 1; // Used by LdapCtx for check for sharing
0117:
0118:            Connection conn; // Connection to server; has reader thread
0119:            // used by LdapCtx for StartTLS
0120:
0121:            final private PoolCallback pcb;
0122:            final private boolean pooled;
0123:            private boolean authenticateCalled = false;
0124:
0125:            ////////////////////////////////////////////////////////////////////////////
0126:            //
0127:            // constructor: Create an authenticated connection to server
0128:            //
0129:            ////////////////////////////////////////////////////////////////////////////
0130:
0131:            LdapClient(String host, int port, String socketFactory,
0132:                    int connectTimeout, int readTimeout, OutputStream trace,
0133:                    PoolCallback pcb) throws NamingException {
0134:
0135:                if (debug > 0)
0136:                    System.err.println("LdapClient: constructor called " + host
0137:                            + ":" + port);
0138:                conn = new Connection(this , host, port, socketFactory,
0139:                        connectTimeout, readTimeout, trace);
0140:
0141:                this .pcb = pcb;
0142:                pooled = (pcb != null);
0143:            }
0144:
0145:            synchronized boolean authenticateCalled() {
0146:                return authenticateCalled;
0147:            }
0148:
0149:            synchronized LdapResult authenticate(boolean initial, String name,
0150:                    Object pw, int version, String authMechanism,
0151:                    Control[] ctls, Hashtable env) throws NamingException {
0152:
0153:                authenticateCalled = true;
0154:
0155:                try {
0156:                    ensureOpen();
0157:                } catch (IOException e) {
0158:                    NamingException ne = new CommunicationException();
0159:                    ne.setRootCause(e);
0160:                    throw ne;
0161:                }
0162:
0163:                switch (version) {
0164:                case LDAP_VERSION3_VERSION2:
0165:                case LDAP_VERSION3:
0166:                    isLdapv3 = true;
0167:                    break;
0168:                case LDAP_VERSION2:
0169:                    isLdapv3 = false;
0170:                    break;
0171:                default:
0172:                    throw new CommunicationException("Protocol version "
0173:                            + version + " not supported");
0174:                }
0175:
0176:                LdapResult res = null;
0177:
0178:                if (authMechanism.equalsIgnoreCase("none")
0179:                        || authMechanism.equalsIgnoreCase("anonymous")) {
0180:
0181:                    // Perform LDAP bind if we are reauthenticating, using LDAPv2,
0182:                    // supporting failover to LDAPv2, or controls have been supplied.
0183:                    if (!initial || (version == LDAP_VERSION2)
0184:                            || (version == LDAP_VERSION3_VERSION2)
0185:                            || ((ctls != null) && (ctls.length > 0))) {
0186:                        try {
0187:                            // anonymous bind; update name/pw for LDAPv2 retry
0188:                            res = ldapBind(name = null, (byte[]) (pw = null),
0189:                                    ctls, null, false);
0190:                            if (res.status == LdapClient.LDAP_SUCCESS) {
0191:                                conn.setBound();
0192:                            }
0193:                        } catch (IOException e) {
0194:                            NamingException ne = new CommunicationException(
0195:                                    "anonymous bind failed: " + conn.host + ":"
0196:                                            + conn.port);
0197:                            ne.setRootCause(e);
0198:                            throw ne;
0199:                        }
0200:                    } else {
0201:                        // Skip LDAP bind for LDAPv3 anonymous bind
0202:                        res = new LdapResult();
0203:                        res.status = LdapClient.LDAP_SUCCESS;
0204:                    }
0205:                } else if (authMechanism.equalsIgnoreCase("simple")) {
0206:                    // simple authentication
0207:                    byte[] encodedPw = null;
0208:                    try {
0209:                        encodedPw = encodePassword(pw, isLdapv3);
0210:                        res = ldapBind(name, encodedPw, ctls, null, false);
0211:                        if (res.status == LdapClient.LDAP_SUCCESS) {
0212:                            conn.setBound();
0213:                        }
0214:                    } catch (IOException e) {
0215:                        NamingException ne = new CommunicationException(
0216:                                "simple bind failed: " + conn.host + ":"
0217:                                        + conn.port);
0218:                        ne.setRootCause(e);
0219:                        throw ne;
0220:                    } finally {
0221:                        // If pw was copied to a new array, clear that array as
0222:                        // a security precaution.
0223:                        if (encodedPw != pw && encodedPw != null) {
0224:                            for (int i = 0; i < encodedPw.length; i++) {
0225:                                encodedPw[i] = 0;
0226:                            }
0227:                        }
0228:                    }
0229:                } else if (isLdapv3) {
0230:                    // SASL authentication
0231:                    try {
0232:                        res = LdapSasl.saslBind(this , conn, conn.host, name,
0233:                                pw, authMechanism, env, ctls);
0234:                        if (res.status == LdapClient.LDAP_SUCCESS) {
0235:                            conn.setBound();
0236:                        }
0237:                    } catch (IOException e) {
0238:                        NamingException ne = new CommunicationException(
0239:                                "SASL bind failed: " + conn.host + ":"
0240:                                        + conn.port);
0241:                        ne.setRootCause(e);
0242:                        throw ne;
0243:                    }
0244:                } else {
0245:                    throw new AuthenticationNotSupportedException(authMechanism);
0246:                }
0247:
0248:                //
0249:                // re-try login using v2 if failing over
0250:                //
0251:                if (initial
0252:                        && (res.status == LdapClient.LDAP_PROTOCOL_ERROR)
0253:                        && (version == LdapClient.LDAP_VERSION3_VERSION2)
0254:                        && (authMechanism.equalsIgnoreCase("none")
0255:                                || authMechanism.equalsIgnoreCase("anonymous") || authMechanism
0256:                                .equalsIgnoreCase("simple"))) {
0257:
0258:                    byte[] encodedPw = null;
0259:                    try {
0260:                        isLdapv3 = false;
0261:                        encodedPw = encodePassword(pw, false);
0262:                        res = ldapBind(name, encodedPw, ctls, null, false);
0263:                        if (res.status == LdapClient.LDAP_SUCCESS) {
0264:                            conn.setBound();
0265:                        }
0266:                    } catch (IOException e) {
0267:                        NamingException ne = new CommunicationException(
0268:                                authMechanism + ":" + conn.host + ":"
0269:                                        + conn.port);
0270:                        ne.setRootCause(e);
0271:                        throw ne;
0272:                    } finally {
0273:                        // If pw was copied to a new array, clear that array as
0274:                        // a security precaution.
0275:                        if (encodedPw != pw && encodedPw != null) {
0276:                            for (int i = 0; i < encodedPw.length; i++) {
0277:                                encodedPw[i] = 0;
0278:                            }
0279:                        }
0280:                    }
0281:                }
0282:
0283:                // principal name not found
0284:                // (map NameNotFoundException to AuthenticationException)
0285:                // %%% This is a workaround for Netscape servers returning
0286:                // %%% no such object when the principal name is not found
0287:                // %%% Note that when this workaround is applied, it does not allow
0288:                // %%% response controls to be recorded by the calling context
0289:                if (res.status == LdapClient.LDAP_NO_SUCH_OBJECT) {
0290:                    throw new AuthenticationException(getErrorMessage(
0291:                            res.status, res.errorMessage));
0292:                }
0293:                conn.setV3(isLdapv3);
0294:                return res;
0295:            }
0296:
0297:            /**
0298:             * Sends an LDAP Bind request.
0299:             * Cannot be private; called by LdapSasl
0300:             * @param dn The possibly null DN to use in the BIND request. null if anonymous.
0301:             * @param toServer The possibly null array of bytes to send to the server.
0302:             * @param auth The authentication mechanism
0303:             *
0304:             */
0305:            synchronized public LdapResult ldapBind(String dn, byte[] toServer,
0306:                    Control[] bindCtls, String auth, boolean pauseAfterReceipt)
0307:                    throws java.io.IOException, NamingException {
0308:
0309:                ensureOpen();
0310:
0311:                // flush outstanding requests
0312:                conn.abandonOutstandingReqs(null);
0313:
0314:                BerEncoder ber = new BerEncoder();
0315:                int curMsgId = conn.getMsgId();
0316:                LdapResult res = new LdapResult();
0317:                res.status = LDAP_OPERATIONS_ERROR;
0318:
0319:                //
0320:                // build the bind request.
0321:                //
0322:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0323:                ber.encodeInt(curMsgId);
0324:                ber.beginSeq(LdapClient.LDAP_REQ_BIND);
0325:                ber.encodeInt(isLdapv3 ? LDAP_VERSION3 : LDAP_VERSION2);
0326:                ber.encodeString(dn, isLdapv3);
0327:
0328:                // if authentication mechanism specified, it is SASL
0329:                if (auth != null) {
0330:                    ber.beginSeq(Ber.ASN_CONTEXT | Ber.ASN_CONSTRUCTOR | 3);
0331:                    ber.encodeString(auth, isLdapv3); // SASL mechanism
0332:                    if (toServer != null) {
0333:                        ber.encodeOctetString(toServer, Ber.ASN_OCTET_STR);
0334:                    }
0335:                    ber.endSeq();
0336:                } else {
0337:                    if (toServer != null) {
0338:                        ber.encodeOctetString(toServer, Ber.ASN_CONTEXT);
0339:                    } else {
0340:                        ber.encodeOctetString(null, Ber.ASN_CONTEXT, 0, 0);
0341:                    }
0342:                }
0343:                ber.endSeq();
0344:
0345:                // Encode controls
0346:                if (isLdapv3) {
0347:                    encodeControls(ber, bindCtls);
0348:                }
0349:                ber.endSeq();
0350:
0351:                LdapRequest req = conn.writeRequest(ber, curMsgId,
0352:                        pauseAfterReceipt);
0353:                if (toServer != null) {
0354:                    ber.reset(); // clear internally-stored password
0355:                }
0356:
0357:                // Read reply
0358:                BerDecoder rber = conn.readReply(req);
0359:
0360:                rber.parseSeq(null); // init seq
0361:                rber.parseInt(); // msg id
0362:                if (rber.parseByte() != LDAP_REP_BIND) {
0363:                    return res;
0364:                }
0365:
0366:                rber.parseLength();
0367:                parseResult(rber, res, isLdapv3);
0368:
0369:                // handle server's credentials (if present)
0370:                if (isLdapv3 && (rber.bytesLeft() > 0)
0371:                        && (rber.peekByte() == (Ber.ASN_CONTEXT | 7))) {
0372:                    res.serverCreds = rber.parseOctetString(
0373:                            (Ber.ASN_CONTEXT | 7), null);
0374:                }
0375:
0376:                res.resControls = isLdapv3 ? parseControls(rber) : null;
0377:
0378:                conn.removeRequest(req);
0379:                return res;
0380:            }
0381:
0382:            /**
0383:             * Determines whether SASL encryption/integrity is in progress.
0384:             * This check is made prior to reauthentication. You cannot reauthenticate
0385:             * over an encrypted/integrity-protected SASL channel. You must
0386:             * close the channel and open a new one.
0387:             */
0388:            boolean usingSaslStreams() {
0389:                return (conn.inStream instanceof  SaslInputStream);
0390:            }
0391:
0392:            synchronized void incRefCount() {
0393:                ++referenceCount;
0394:                if (debug > 1) {
0395:                    System.err.println("LdapClient.incRefCount: "
0396:                            + referenceCount + " " + this );
0397:                }
0398:
0399:            }
0400:
0401:            /**
0402:             * Returns the encoded password.
0403:             */
0404:            private static byte[] encodePassword(Object pw, boolean v3)
0405:                    throws IOException {
0406:
0407:                if (pw instanceof  char[]) {
0408:                    pw = new String((char[]) pw);
0409:                }
0410:
0411:                if (pw instanceof  String) {
0412:                    if (v3) {
0413:                        return ((String) pw).getBytes("UTF8");
0414:                    } else {
0415:                        return ((String) pw).getBytes("8859_1");
0416:                    }
0417:                } else {
0418:                    return (byte[]) pw;
0419:                }
0420:            }
0421:
0422:            synchronized void close(Control[] reqCtls, boolean hardClose) {
0423:                --referenceCount;
0424:
0425:                if (debug > 1) {
0426:                    System.err.println("LdapClient: " + this );
0427:                    System.err.println("LdapClient: close() called: "
0428:                            + referenceCount);
0429:                    (new Throwable()).printStackTrace();
0430:                }
0431:
0432:                if (referenceCount <= 0 && conn != null) {
0433:                    if (debug > 0)
0434:                        System.err.println("LdapClient: closed connection "
0435:                                + this );
0436:                    if (!pooled) {
0437:                        // Not being pooled; continue with closing
0438:                        conn.cleanup(reqCtls, false);
0439:                        conn = null;
0440:                    } else {
0441:                        // Pooled
0442:
0443:                        // Is this a real close or a request to return conn to pool
0444:                        if (hardClose) {
0445:                            conn.cleanup(reqCtls, false);
0446:                            conn = null;
0447:                            pcb.removePooledConnection(this );
0448:                        } else {
0449:                            pcb.releasePooledConnection(this );
0450:                        }
0451:                    }
0452:                }
0453:            }
0454:
0455:            // NOTE: Should NOT be synchronized otherwise won't be able to close
0456:            private void forceClose(boolean cleanPool) {
0457:                referenceCount = 0; // force closing of connection
0458:
0459:                if (debug > 1) {
0460:                    System.err.println("LdapClient: forceClose() of " + this );
0461:                }
0462:
0463:                if (conn != null) {
0464:                    if (debug > 0)
0465:                        System.err
0466:                                .println("LdapClient: forced close of connection "
0467:                                        + this );
0468:                    conn.cleanup(null, false);
0469:                    conn = null;
0470:
0471:                    if (cleanPool) {
0472:                        pcb.removePooledConnection(this );
0473:                    }
0474:                }
0475:            }
0476:
0477:            protected void finalize() {
0478:                if (debug > 0)
0479:                    System.err.println("LdapClient: finalize " + this );
0480:                forceClose(pooled);
0481:            }
0482:
0483:            /*
0484:             * Used by connection pooling to close physical connection.
0485:             */
0486:            synchronized public void closeConnection() {
0487:                forceClose(false); // this is a pool callback so no need to clean pool
0488:            }
0489:
0490:            /**
0491:             * Called by Connection.cleanup(). LdapClient should
0492:             * notify any unsolicited listeners and removing itself from any pool.
0493:             * This is almost like forceClose(), except it doesn't call 
0494:             * Connection.cleanup() (because this is called from cleanup()).
0495:             */
0496:            void processConnectionClosure() {
0497:                // Notify listeners
0498:                if (unsolicited.size() > 0) {
0499:                    String msg;
0500:                    if (conn != null) {
0501:                        msg = conn.host + ":" + conn.port
0502:                                + " connection closed";
0503:                    } else {
0504:                        msg = "Connection closed";
0505:                    }
0506:                    notifyUnsolicited(new CommunicationException(msg));
0507:                }
0508:
0509:                // Remove from pool
0510:                if (pooled) {
0511:                    pcb.removePooledConnection(this );
0512:                }
0513:            }
0514:
0515:            ////////////////////////////////////////////////////////////////////////////
0516:            //
0517:            // LDAP search. also includes methods to encode rfc 1558 compliant filters
0518:            //
0519:            ////////////////////////////////////////////////////////////////////////////
0520:
0521:            static final int SCOPE_BASE_OBJECT = 0;
0522:            static final int SCOPE_ONE_LEVEL = 1;
0523:            static final int SCOPE_SUBTREE = 2;
0524:
0525:            LdapResult search(String dn, int scope, int deref, int sizeLimit,
0526:                    int timeLimit, boolean attrsOnly, String attrs[],
0527:                    String filter, int batchSize, Control[] reqCtls,
0528:                    Hashtable binaryAttrs, boolean waitFirstReply)
0529:                    throws IOException, NamingException {
0530:
0531:                ensureOpen();
0532:
0533:                LdapResult res = new LdapResult();
0534:
0535:                BerEncoder ber = new BerEncoder();
0536:                int curMsgId = conn.getMsgId();
0537:
0538:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0539:                ber.encodeInt(curMsgId);
0540:                ber.beginSeq(LDAP_REQ_SEARCH);
0541:                ber.encodeString(dn == null ? "" : dn, isLdapv3);
0542:                ber.encodeInt(scope, LBER_ENUMERATED);
0543:                ber.encodeInt(deref, LBER_ENUMERATED);
0544:                ber.encodeInt(sizeLimit);
0545:                ber.encodeInt(timeLimit);
0546:                ber.encodeBoolean(attrsOnly);
0547:                Filter.encodeFilterString(ber, filter, isLdapv3);
0548:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0549:                ber.encodeStringArray(attrs, isLdapv3);
0550:                ber.endSeq();
0551:                ber.endSeq();
0552:                if (isLdapv3)
0553:                    encodeControls(ber, reqCtls);
0554:                ber.endSeq();
0555:
0556:                LdapRequest req = conn.writeRequest(ber, curMsgId);
0557:
0558:                res.msgId = curMsgId;
0559:                res.status = LdapClient.LDAP_SUCCESS; //optimistic
0560:                if (waitFirstReply) {
0561:                    // get first reply
0562:                    res = getSearchReply(req, batchSize, res, binaryAttrs);
0563:                }
0564:                return res;
0565:            }
0566:
0567:            /*
0568:             * Abandon the search operation and remove it from the message queue.
0569:             */
0570:            void clearSearchReply(LdapResult res, Control[] ctls) {
0571:                if (res != null && conn != null) {
0572:
0573:                    // Only send an LDAP abandon operation when clearing the search
0574:                    // reply from a one-level or subtree search.
0575:                    LdapRequest req = conn.findRequest(res.msgId);
0576:                    if (req == null) {
0577:                        return;
0578:                    }
0579:
0580:                    // OK if req got removed after check; double removal attempt
0581:                    // but otherwise no harm done
0582:
0583:                    // Send an LDAP abandon only if the search operation has not yet
0584:                    // completed.
0585:                    if (req.hasSearchCompleted()) {
0586:                        conn.removeRequest(req);
0587:                    } else {
0588:                        conn.abandonRequest(req, ctls);
0589:                    }
0590:                }
0591:            }
0592:
0593:            /*
0594:             * Retrieve the next batch of entries and/or referrals.
0595:             */
0596:            LdapResult getSearchReply(int batchSize, LdapResult res,
0597:                    Hashtable binaryAttrs) throws IOException, NamingException {
0598:
0599:                ensureOpen();
0600:
0601:                LdapRequest req;
0602:
0603:                if ((req = conn.findRequest(res.msgId)) == null) {
0604:                    return null;
0605:                }
0606:
0607:                return getSearchReply(req, batchSize, res, binaryAttrs);
0608:            }
0609:
0610:            private LdapResult getSearchReply(LdapRequest req, int batchSize,
0611:                    LdapResult res, Hashtable binaryAttrs) throws IOException,
0612:                    NamingException {
0613:
0614:                if (batchSize == 0)
0615:                    batchSize = Integer.MAX_VALUE;
0616:
0617:                if (res.entries != null) {
0618:                    res.entries.setSize(0); // clear the (previous) set of entries
0619:                } else {
0620:                    res.entries = new Vector(
0621:                            batchSize == Integer.MAX_VALUE ? 32 : batchSize);
0622:                }
0623:
0624:                if (res.referrals != null) {
0625:                    res.referrals.setSize(0); // clear the (previous) set of referrals
0626:                }
0627:
0628:                BerDecoder replyBer; // Decoder for response
0629:                int seq; // Request id
0630:
0631:                Attributes lattrs; // Attribute set read from response
0632:                Attribute la; // Attribute read from response
0633:                String DN; // DN read from response
0634:                LdapEntry le; // LDAP entry representing response
0635:                int[] seqlen; // Holder for response length
0636:                int endseq; // Position of end of response
0637:
0638:                for (int i = 0; i < batchSize;) {
0639:                    replyBer = conn.readReply(req);
0640:
0641:                    //
0642:                    // process search reply
0643:                    //
0644:                    replyBer.parseSeq(null); // init seq
0645:                    replyBer.parseInt(); // req id
0646:                    seq = replyBer.parseSeq(null);
0647:
0648:                    if (seq == LDAP_REP_SEARCH) {
0649:
0650:                        // handle LDAPv3 search entries
0651:                        lattrs = new BasicAttributes(caseIgnore);
0652:                        DN = replyBer.parseString(isLdapv3);
0653:                        le = new LdapEntry(DN, lattrs);
0654:                        seqlen = new int[1];
0655:
0656:                        replyBer.parseSeq(seqlen);
0657:                        endseq = replyBer.getParsePosition() + seqlen[0];
0658:                        while ((replyBer.getParsePosition() < endseq)
0659:                                && (replyBer.bytesLeft() > 0)) {
0660:                            la = parseAttribute(replyBer, binaryAttrs);
0661:                            lattrs.put(la);
0662:                        }
0663:                        le.respCtls = isLdapv3 ? parseControls(replyBer) : null;
0664:
0665:                        res.entries.addElement(le);
0666:                        i++;
0667:
0668:                    } else if ((seq == LDAP_REP_SEARCH_REF) && isLdapv3) {
0669:
0670:                        // handle LDAPv3 search reference
0671:                        Vector URLs = new Vector(4);
0672:
0673:                        // %%% Although not strictly correct, some LDAP servers
0674:                        //     encode the SEQUENCE OF tag in the SearchResultRef
0675:                        if (replyBer.peekByte() == (Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR)) {
0676:                            replyBer.parseSeq(null);
0677:                        }
0678:
0679:                        while ((replyBer.bytesLeft() > 0)
0680:                                && (replyBer.peekByte() == Ber.ASN_OCTET_STR)) {
0681:
0682:                            URLs.addElement(replyBer.parseString(isLdapv3));
0683:                        }
0684:
0685:                        if (res.referrals == null) {
0686:                            res.referrals = new Vector(4);
0687:                        }
0688:                        res.referrals.addElement(URLs);
0689:                        res.resControls = isLdapv3 ? parseControls(replyBer)
0690:                                : null;
0691:
0692:                        // Save referral and continue to get next search result
0693:
0694:                    } else if (seq == LDAP_REP_EXTENSION) {
0695:
0696:                        parseExtResponse(replyBer, res); //%%% ignore for now
0697:
0698:                    } else if (seq == LDAP_REP_RESULT) {
0699:
0700:                        parseResult(replyBer, res, isLdapv3);
0701:                        res.resControls = isLdapv3 ? parseControls(replyBer)
0702:                                : null;
0703:
0704:                        conn.removeRequest(req);
0705:                        return res; // Done with search
0706:                    }
0707:                }
0708:
0709:                return res;
0710:            }
0711:
0712:            private Attribute parseAttribute(BerDecoder ber,
0713:                    Hashtable binaryAttrs) throws IOException {
0714:
0715:                int len[] = new int[1];
0716:                int seq = ber.parseSeq(null);
0717:                String attrid = ber.parseString(isLdapv3);
0718:                boolean hasBinaryValues = isBinaryValued(attrid, binaryAttrs);
0719:                Attribute la = new LdapAttribute(attrid);
0720:
0721:                if ((seq = ber.parseSeq(len)) == LBER_SET) {
0722:                    int attrlen = len[0];
0723:                    while (ber.bytesLeft() > 0 && attrlen > 0) {
0724:                        try {
0725:                            attrlen -= parseAttributeValue(ber, la,
0726:                                    hasBinaryValues);
0727:                        } catch (IOException ex) {
0728:                            ber.seek(attrlen);
0729:                            break;
0730:                        }
0731:                    }
0732:                } else {
0733:                    // Skip the rest of the sequence because it is not what we want
0734:                    ber.seek(len[0]);
0735:                }
0736:                return la;
0737:            }
0738:
0739:            //
0740:            // returns number of bytes that were parsed. Adds the values to attr
0741:            //
0742:            private int parseAttributeValue(BerDecoder ber, Attribute la,
0743:                    boolean hasBinaryValues) throws IOException {
0744:
0745:                int len[] = new int[1];
0746:
0747:                if (hasBinaryValues) {
0748:                    la.add(ber.parseOctetString(ber.peekByte(), len));
0749:                } else {
0750:                    la.add(ber.parseStringWithTag(Ber.ASN_SIMPLE_STRING,
0751:                            isLdapv3, len));
0752:                }
0753:                return len[0];
0754:            }
0755:
0756:            private boolean isBinaryValued(String attrid, Hashtable binaryAttrs) {
0757:                String id = attrid.toLowerCase();
0758:
0759:                return ((id.indexOf(";binary") != -1)
0760:                        || defaultBinaryAttrs.containsKey(id) || ((binaryAttrs != null) && (binaryAttrs
0761:                        .containsKey(id))));
0762:            }
0763:
0764:            // package entry point; used by Connection
0765:            static void parseResult(BerDecoder replyBer, LdapResult res,
0766:                    boolean isLdapv3) throws IOException {
0767:
0768:                res.status = replyBer.parseEnumeration();
0769:                res.matchedDN = replyBer.parseString(isLdapv3);
0770:                res.errorMessage = replyBer.parseString(isLdapv3);
0771:
0772:                // handle LDAPv3 referrals (if present)
0773:                if (isLdapv3 && (replyBer.bytesLeft() > 0)
0774:                        && (replyBer.peekByte() == LDAP_REP_REFERRAL)) {
0775:
0776:                    Vector URLs = new Vector(4);
0777:                    int[] seqlen = new int[1];
0778:
0779:                    replyBer.parseSeq(seqlen);
0780:                    int endseq = replyBer.getParsePosition() + seqlen[0];
0781:                    while ((replyBer.getParsePosition() < endseq)
0782:                            && (replyBer.bytesLeft() > 0)) {
0783:
0784:                        URLs.addElement(replyBer.parseString(isLdapv3));
0785:                    }
0786:
0787:                    if (res.referrals == null) {
0788:                        res.referrals = new Vector(4);
0789:                    }
0790:                    res.referrals.addElement(URLs);
0791:                }
0792:            }
0793:
0794:            // package entry point; used by Connection
0795:            static Vector parseControls(BerDecoder replyBer) throws IOException {
0796:
0797:                // handle LDAPv3 controls (if present)
0798:                if ((replyBer.bytesLeft() > 0)
0799:                        && (replyBer.peekByte() == LDAP_CONTROLS)) {
0800:                    Vector ctls = new Vector(4);
0801:                    String controlOID;
0802:                    boolean criticality = false; // default
0803:                    byte[] controlValue = null; // optional
0804:                    int[] seqlen = new int[1];
0805:
0806:                    replyBer.parseSeq(seqlen);
0807:                    int endseq = replyBer.getParsePosition() + seqlen[0];
0808:                    while ((replyBer.getParsePosition() < endseq)
0809:                            && (replyBer.bytesLeft() > 0)) {
0810:
0811:                        replyBer.parseSeq(null);
0812:                        controlOID = replyBer.parseString(true);
0813:
0814:                        if ((replyBer.bytesLeft() > 0)
0815:                                && (replyBer.peekByte() == Ber.ASN_BOOLEAN)) {
0816:                            criticality = replyBer.parseBoolean();
0817:                        }
0818:                        if ((replyBer.bytesLeft() > 0)
0819:                                && (replyBer.peekByte() == Ber.ASN_OCTET_STR)) {
0820:                            controlValue = replyBer.parseOctetString(
0821:                                    Ber.ASN_OCTET_STR, null);
0822:                        }
0823:                        if (controlOID != null) {
0824:                            ctls.addElement(new BasicControl(controlOID,
0825:                                    criticality, controlValue));
0826:                        }
0827:                    }
0828:                    return ctls;
0829:                } else {
0830:                    return null;
0831:                }
0832:            }
0833:
0834:            private void parseExtResponse(BerDecoder replyBer, LdapResult res)
0835:                    throws IOException {
0836:
0837:                parseResult(replyBer, res, isLdapv3);
0838:
0839:                if ((replyBer.bytesLeft() > 0)
0840:                        && (replyBer.peekByte() == LDAP_REP_EXT_OID)) {
0841:                    res.extensionId = replyBer.parseStringWithTag(
0842:                            LDAP_REP_EXT_OID, isLdapv3, null);
0843:                }
0844:                if ((replyBer.bytesLeft() > 0)
0845:                        && (replyBer.peekByte() == LDAP_REP_EXT_VAL)) {
0846:                    res.extensionValue = replyBer.parseOctetString(
0847:                            LDAP_REP_EXT_VAL, null);
0848:                }
0849:
0850:                res.resControls = parseControls(replyBer);
0851:            }
0852:
0853:            //
0854:            // Encode LDAPv3 controls
0855:            //
0856:            static void encodeControls(BerEncoder ber, Control[] reqCtls)
0857:                    throws IOException {
0858:
0859:                if ((reqCtls == null) || (reqCtls.length == 0)) {
0860:                    return;
0861:                }
0862:
0863:                byte[] controlVal;
0864:
0865:                ber.beginSeq(LdapClient.LDAP_CONTROLS);
0866:
0867:                for (int i = 0; i < reqCtls.length; i++) {
0868:                    ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0869:                    ber.encodeString(reqCtls[i].getID(), true); // control OID
0870:                    if (reqCtls[i].isCritical()) {
0871:                        ber.encodeBoolean(true); // critical control
0872:                    }
0873:                    if ((controlVal = reqCtls[i].getEncodedValue()) != null) {
0874:                        ber.encodeOctetString(controlVal, Ber.ASN_OCTET_STR);
0875:                    }
0876:                    ber.endSeq();
0877:                }
0878:                ber.endSeq();
0879:            }
0880:
0881:            /**
0882:             * Reads the next reply corresponding to msgId, outstanding on requestBer.
0883:             * Processes the result and any controls.
0884:             */
0885:            private LdapResult processReply(LdapRequest req, LdapResult res,
0886:                    int responseType) throws IOException, NamingException {
0887:
0888:                BerDecoder rber = conn.readReply(req);
0889:
0890:                rber.parseSeq(null); // init seq
0891:                rber.parseInt(); // msg id
0892:                if (rber.parseByte() != responseType) {
0893:                    return res;
0894:                }
0895:
0896:                rber.parseLength();
0897:                parseResult(rber, res, isLdapv3);
0898:                res.resControls = isLdapv3 ? parseControls(rber) : null;
0899:
0900:                conn.removeRequest(req);
0901:
0902:                return res; // Done with operation
0903:            }
0904:
0905:            ////////////////////////////////////////////////////////////////////////////
0906:            //
0907:            // LDAP modify:
0908:            //	Modify the DN dn with the operations on attributes attrs.
0909:            //	ie, operations[0] is the operation to be performed on
0910:            //	attrs[0];
0911:            //		dn - DN to modify
0912:            //		operations - add, delete or replace
0913:            //		attrs - array of Attribute
0914:            //		reqCtls - array of request controls
0915:            //
0916:            ////////////////////////////////////////////////////////////////////////////
0917:
0918:            static final int ADD = 0;
0919:            static final int DELETE = 1;
0920:            static final int REPLACE = 2;
0921:
0922:            LdapResult modify(String dn, int operations[], Attribute attrs[],
0923:                    Control[] reqCtls) throws IOException, NamingException {
0924:
0925:                ensureOpen();
0926:
0927:                LdapResult res = new LdapResult();
0928:                res.status = LDAP_OPERATIONS_ERROR;
0929:
0930:                if (dn == null || operations.length != attrs.length)
0931:                    return res;
0932:
0933:                BerEncoder ber = new BerEncoder();
0934:                int curMsgId = conn.getMsgId();
0935:
0936:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0937:                ber.encodeInt(curMsgId);
0938:                ber.beginSeq(LDAP_REQ_MODIFY);
0939:                ber.encodeString(dn, isLdapv3);
0940:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0941:                for (int i = 0; i < operations.length; i++) {
0942:                    ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0943:                    ber.encodeInt(operations[i], LBER_ENUMERATED);
0944:
0945:                    // zero values is not permitted for the add op. 
0946:                    if ((operations[i] == ADD) && hasNoValue(attrs[i])) {
0947:                        throw new InvalidAttributeValueException("'"
0948:                                + attrs[i].getID() + "' has no values.");
0949:                    } else {
0950:                        encodeAttribute(ber, attrs[i]);
0951:                    }
0952:                    ber.endSeq();
0953:                }
0954:                ber.endSeq();
0955:                ber.endSeq();
0956:                if (isLdapv3)
0957:                    encodeControls(ber, reqCtls);
0958:                ber.endSeq();
0959:
0960:                LdapRequest req = conn.writeRequest(ber, curMsgId);
0961:
0962:                return processReply(req, res, LDAP_REP_MODIFY);
0963:            }
0964:
0965:            private void encodeAttribute(BerEncoder ber, Attribute attr)
0966:                    throws IOException, NamingException {
0967:
0968:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
0969:                ber.encodeString(attr.getID(), isLdapv3);
0970:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR | 1);
0971:                NamingEnumeration enum_ = attr.getAll();
0972:                Object val;
0973:                while (enum_.hasMore()) {
0974:                    val = enum_.next();
0975:                    if (val instanceof  String) {
0976:                        ber.encodeString((String) val, isLdapv3);
0977:                    } else if (val instanceof  byte[]) {
0978:                        ber.encodeOctetString((byte[]) val, Ber.ASN_OCTET_STR);
0979:                    } else if (val == null) {
0980:                        // no attribute value
0981:                    } else {
0982:                        throw new InvalidAttributeValueException("Malformed '"
0983:                                + attr.getID() + "' attribute value");
0984:                    }
0985:                }
0986:                ber.endSeq();
0987:                ber.endSeq();
0988:            }
0989:
0990:            private static boolean hasNoValue(Attribute attr)
0991:                    throws NamingException {
0992:                return attr.size() == 0
0993:                        || (attr.size() == 1 && attr.get() == null);
0994:            }
0995:
0996:            ////////////////////////////////////////////////////////////////////////////
0997:            //
0998:            // LDAP add
0999:            //		Adds entry to the Directory
1000:            //
1001:            ////////////////////////////////////////////////////////////////////////////
1002:
1003:            LdapResult add(LdapEntry entry, Control[] reqCtls)
1004:                    throws IOException, NamingException {
1005:
1006:                ensureOpen();
1007:
1008:                LdapResult res = new LdapResult();
1009:                res.status = LDAP_OPERATIONS_ERROR;
1010:
1011:                if (entry == null || entry.DN == null)
1012:                    return res;
1013:
1014:                BerEncoder ber = new BerEncoder();
1015:                int curMsgId = conn.getMsgId();
1016:                Attribute attr;
1017:
1018:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1019:                ber.encodeInt(curMsgId);
1020:                ber.beginSeq(LDAP_REQ_ADD);
1021:                ber.encodeString(entry.DN, isLdapv3);
1022:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1023:                NamingEnumeration enum_ = entry.attributes.getAll();
1024:                while (enum_.hasMore()) {
1025:                    attr = (Attribute) enum_.next();
1026:
1027:                    // zero values is not permitted
1028:                    if (hasNoValue(attr)) {
1029:                        throw new InvalidAttributeValueException("'"
1030:                                + attr.getID() + "' has no values.");
1031:                    } else {
1032:                        encodeAttribute(ber, attr);
1033:                    }
1034:                }
1035:                ber.endSeq();
1036:                ber.endSeq();
1037:                if (isLdapv3)
1038:                    encodeControls(ber, reqCtls);
1039:                ber.endSeq();
1040:
1041:                LdapRequest req = conn.writeRequest(ber, curMsgId);
1042:                return processReply(req, res, LDAP_REP_ADD);
1043:            }
1044:
1045:            ////////////////////////////////////////////////////////////////////////////
1046:            //
1047:            // LDAP delete
1048:            //		deletes entry from the Directory
1049:            //
1050:            ////////////////////////////////////////////////////////////////////////////
1051:
1052:            LdapResult delete(String DN, Control[] reqCtls) throws IOException,
1053:                    NamingException {
1054:
1055:                ensureOpen();
1056:
1057:                LdapResult res = new LdapResult();
1058:                res.status = LDAP_OPERATIONS_ERROR;
1059:
1060:                if (DN == null)
1061:                    return res;
1062:
1063:                BerEncoder ber = new BerEncoder();
1064:                int curMsgId = conn.getMsgId();
1065:
1066:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1067:                ber.encodeInt(curMsgId);
1068:                ber.encodeString(DN, LDAP_REQ_DELETE, isLdapv3);
1069:                if (isLdapv3)
1070:                    encodeControls(ber, reqCtls);
1071:                ber.endSeq();
1072:
1073:                LdapRequest req = conn.writeRequest(ber, curMsgId);
1074:
1075:                return processReply(req, res, LDAP_REP_DELETE);
1076:            }
1077:
1078:            ////////////////////////////////////////////////////////////////////////////
1079:            //
1080:            // LDAP modrdn
1081:            //	Changes the last element of DN to newrdn
1082:            //		dn - DN to change
1083:            //		newrdn - new RDN to rename to
1084:            //		deleteoldrdn - boolean whether to delete old attrs or not
1085:            //		newSuperior - new place to put the entry in the tree
1086:            //			      (ignored if server is LDAPv2)
1087:            //		reqCtls - array of request controls
1088:            //
1089:            ////////////////////////////////////////////////////////////////////////////
1090:
1091:            LdapResult moddn(String DN, String newrdn, boolean deleteOldRdn,
1092:                    String newSuperior, Control[] reqCtls) throws IOException,
1093:                    NamingException {
1094:
1095:                ensureOpen();
1096:
1097:                boolean changeSuperior = (newSuperior != null && newSuperior
1098:                        .length() > 0);
1099:
1100:                LdapResult res = new LdapResult();
1101:                res.status = LDAP_OPERATIONS_ERROR;
1102:
1103:                if (DN == null || newrdn == null)
1104:                    return res;
1105:
1106:                BerEncoder ber = new BerEncoder();
1107:                int curMsgId = conn.getMsgId();
1108:
1109:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1110:                ber.encodeInt(curMsgId);
1111:                ber.beginSeq(LDAP_REQ_MODRDN);
1112:                ber.encodeString(DN, isLdapv3);
1113:                ber.encodeString(newrdn, isLdapv3);
1114:                ber.encodeBoolean(deleteOldRdn);
1115:                if (isLdapv3 && changeSuperior) {
1116:                    //System.err.println("changin superior");
1117:                    ber.encodeString(newSuperior, LDAP_SUPERIOR_DN, isLdapv3);
1118:                }
1119:                ber.endSeq();
1120:                if (isLdapv3)
1121:                    encodeControls(ber, reqCtls);
1122:                ber.endSeq();
1123:
1124:                LdapRequest req = conn.writeRequest(ber, curMsgId);
1125:
1126:                return processReply(req, res, LDAP_REP_MODRDN);
1127:            }
1128:
1129:            ////////////////////////////////////////////////////////////////////////////
1130:            //
1131:            // LDAP compare
1132:            //	Compare attribute->value pairs in dn
1133:            //
1134:            ////////////////////////////////////////////////////////////////////////////
1135:
1136:            LdapResult compare(String DN, String type, String value,
1137:                    Control[] reqCtls) throws IOException, NamingException {
1138:
1139:                ensureOpen();
1140:
1141:                LdapResult res = new LdapResult();
1142:                res.status = LDAP_OPERATIONS_ERROR;
1143:
1144:                if (DN == null || type == null || value == null)
1145:                    return res;
1146:
1147:                BerEncoder ber = new BerEncoder();
1148:                int curMsgId = conn.getMsgId();
1149:
1150:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1151:                ber.encodeInt(curMsgId);
1152:                ber.beginSeq(LDAP_REQ_COMPARE);
1153:                ber.encodeString(DN, isLdapv3);
1154:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1155:                ber.encodeString(type, isLdapv3);
1156:
1157:                // replace any escaped characters in the value
1158:                byte[] val = isLdapv3 ? value.getBytes("UTF8") : value
1159:                        .getBytes("8859_1");
1160:                ber.encodeOctetString(Filter.unescapeFilterValue(val, 0,
1161:                        val.length), Ber.ASN_OCTET_STR);
1162:
1163:                ber.endSeq();
1164:                ber.endSeq();
1165:                if (isLdapv3)
1166:                    encodeControls(ber, reqCtls);
1167:                ber.endSeq();
1168:
1169:                LdapRequest req = conn.writeRequest(ber, curMsgId);
1170:
1171:                return processReply(req, res, LDAP_REP_COMPARE);
1172:            }
1173:
1174:            ////////////////////////////////////////////////////////////////////////////
1175:            //
1176:            // LDAP extended operation
1177:            //
1178:            ////////////////////////////////////////////////////////////////////////////
1179:
1180:            LdapResult extendedOp(String id, byte[] request, Control[] reqCtls,
1181:                    boolean pauseAfterReceipt) throws IOException,
1182:                    NamingException {
1183:
1184:                ensureOpen();
1185:
1186:                LdapResult res = new LdapResult();
1187:                res.status = LDAP_OPERATIONS_ERROR;
1188:
1189:                if (id == null)
1190:                    return res;
1191:
1192:                BerEncoder ber = new BerEncoder();
1193:                int curMsgId = conn.getMsgId();
1194:
1195:                ber.beginSeq(Ber.ASN_SEQUENCE | Ber.ASN_CONSTRUCTOR);
1196:                ber.encodeInt(curMsgId);
1197:                ber.beginSeq(LDAP_REQ_EXTENSION);
1198:                ber.encodeString(id, Ber.ASN_CONTEXT | 0, isLdapv3);//[0]
1199:                if (request != null) {
1200:                    ber.encodeOctetString(request, Ber.ASN_CONTEXT | 1);//[1]
1201:                }
1202:                ber.endSeq();
1203:                encodeControls(ber, reqCtls); // always v3
1204:                ber.endSeq();
1205:
1206:                LdapRequest req = conn.writeRequest(ber, curMsgId,
1207:                        pauseAfterReceipt);
1208:
1209:                BerDecoder rber = conn.readReply(req);
1210:
1211:                rber.parseSeq(null); // init seq
1212:                rber.parseInt(); // msg id
1213:                if (rber.parseByte() != LDAP_REP_EXTENSION) {
1214:                    return res;
1215:                }
1216:
1217:                rber.parseLength();
1218:                parseExtResponse(rber, res);
1219:                conn.removeRequest(req);
1220:
1221:                return res; // Done with operation
1222:            }
1223:
1224:            ////////////////////////////////////////////////////////////////////////////
1225:            //
1226:            // Some BER definitions convenient for LDAP
1227:            //
1228:            ////////////////////////////////////////////////////////////////////////////
1229:
1230:            static final int LDAP_VERSION3_VERSION2 = 32;
1231:            static final int LDAP_VERSION2 = 0x02;
1232:            static final int LDAP_VERSION3 = 0x03; // LDAPv3
1233:            static final int LDAP_VERSION = LDAP_VERSION3;
1234:
1235:            static final int LDAP_REF_FOLLOW = 0x01; // follow referrals
1236:            static final int LDAP_REF_THROW = 0x02; // throw referral ex.
1237:            static final int LDAP_REF_IGNORE = 0x03; // ignore referrals
1238:
1239:            static final String LDAP_URL = "ldap://"; // LDAPv3
1240:            static final String LDAPS_URL = "ldaps://"; // LDAPv3
1241:
1242:            static final int LBER_BOOLEAN = 0x01;
1243:            static final int LBER_INTEGER = 0x02;
1244:            static final int LBER_BITSTRING = 0x03;
1245:            static final int LBER_OCTETSTRING = 0x04;
1246:            static final int LBER_NULL = 0x05;
1247:            static final int LBER_ENUMERATED = 0x0a;
1248:            static final int LBER_SEQUENCE = 0x30;
1249:            static final int LBER_SET = 0x31;
1250:
1251:            static final int LDAP_SUPERIOR_DN = 0x80;
1252:
1253:            static final int LDAP_REQ_BIND = 0x60; // app + constructed
1254:            static final int LDAP_REQ_UNBIND = 0x42; // app + primitive
1255:            static final int LDAP_REQ_SEARCH = 0x63; // app + constructed
1256:            static final int LDAP_REQ_MODIFY = 0x66; // app + constructed
1257:            static final int LDAP_REQ_ADD = 0x68; // app + constructed
1258:            static final int LDAP_REQ_DELETE = 0x4a; // app + primitive
1259:            static final int LDAP_REQ_MODRDN = 0x6c; // app + constructed
1260:            static final int LDAP_REQ_COMPARE = 0x6e; // app + constructed
1261:            static final int LDAP_REQ_ABANDON = 0x50; // app + primitive
1262:            static final int LDAP_REQ_EXTENSION = 0x77; // app + constructed    (LDAPv3)
1263:
1264:            static final int LDAP_REP_BIND = 0x61; // app + constructed | 1
1265:            static final int LDAP_REP_SEARCH = 0x64; // app + constructed | 4
1266:            static final int LDAP_REP_SEARCH_REF = 0x73;// app + constructed    (LDAPv3)
1267:            static final int LDAP_REP_RESULT = 0x65; // app + constructed | 5
1268:            static final int LDAP_REP_MODIFY = 0x67; // app + constructed | 7
1269:            static final int LDAP_REP_ADD = 0x69; // app + constructed | 9
1270:            static final int LDAP_REP_DELETE = 0x6b; // app + primitive | b
1271:            static final int LDAP_REP_MODRDN = 0x6d; // app + primitive | d
1272:            static final int LDAP_REP_COMPARE = 0x6f; // app + primitive | f
1273:            static final int LDAP_REP_EXTENSION = 0x78; // app + constructed    (LDAPv3)
1274:
1275:            static final int LDAP_REP_REFERRAL = 0xa3; // ctx + constructed    (LDAPv3)
1276:            static final int LDAP_REP_EXT_OID = 0x8a; // ctx + primitive      (LDAPv3)
1277:            static final int LDAP_REP_EXT_VAL = 0x8b; // ctx + primitive      (LDAPv3)
1278:
1279:            // LDAPv3 Controls
1280:
1281:            static final int LDAP_CONTROLS = 0xa0; // ctx + constructed    (LDAPv3)
1282:            static final String LDAP_CONTROL_MANAGE_DSA_IT = "2.16.840.1.113730.3.4.2";
1283:            static final String LDAP_CONTROL_PREFERRED_LANG = "1.3.6.1.4.1.1466.20035";
1284:            static final String LDAP_CONTROL_PAGED_RESULTS = "1.2.840.113556.1.4.319";
1285:            static final String LDAP_CONTROL_SERVER_SORT_REQ = "1.2.840.113556.1.4.473";
1286:            static final String LDAP_CONTROL_SERVER_SORT_RES = "1.2.840.113556.1.4.474";
1287:
1288:            ////////////////////////////////////////////////////////////////////////////
1289:            //
1290:            // return codes
1291:            //
1292:            ////////////////////////////////////////////////////////////////////////////
1293:
1294:            static final int LDAP_SUCCESS = 0;
1295:            static final int LDAP_OPERATIONS_ERROR = 1;
1296:            static final int LDAP_PROTOCOL_ERROR = 2;
1297:            static final int LDAP_TIME_LIMIT_EXCEEDED = 3;
1298:            static final int LDAP_SIZE_LIMIT_EXCEEDED = 4;
1299:            static final int LDAP_COMPARE_FALSE = 5;
1300:            static final int LDAP_COMPARE_TRUE = 6;
1301:            static final int LDAP_AUTH_METHOD_NOT_SUPPORTED = 7;
1302:            static final int LDAP_STRONG_AUTH_REQUIRED = 8;
1303:            static final int LDAP_PARTIAL_RESULTS = 9; // Slapd
1304:            static final int LDAP_REFERRAL = 10; // LDAPv3
1305:            static final int LDAP_ADMIN_LIMIT_EXCEEDED = 11; // LDAPv3
1306:            static final int LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12; // LDAPv3
1307:            static final int LDAP_CONFIDENTIALITY_REQUIRED = 13; // LDAPv3
1308:            static final int LDAP_SASL_BIND_IN_PROGRESS = 14; // LDAPv3
1309:            static final int LDAP_NO_SUCH_ATTRIBUTE = 16;
1310:            static final int LDAP_UNDEFINED_ATTRIBUTE_TYPE = 17;
1311:            static final int LDAP_INAPPROPRIATE_MATCHING = 18;
1312:            static final int LDAP_CONSTRAINT_VIOLATION = 19;
1313:            static final int LDAP_ATTRIBUTE_OR_VALUE_EXISTS = 20;
1314:            static final int LDAP_INVALID_ATTRIBUTE_SYNTAX = 21;
1315:            static final int LDAP_NO_SUCH_OBJECT = 32;
1316:            static final int LDAP_ALIAS_PROBLEM = 33;
1317:            static final int LDAP_INVALID_DN_SYNTAX = 34;
1318:            static final int LDAP_IS_LEAF = 35;
1319:            static final int LDAP_ALIAS_DEREFERENCING_PROBLEM = 36;
1320:            static final int LDAP_INAPPROPRIATE_AUTHENTICATION = 48;
1321:            static final int LDAP_INVALID_CREDENTIALS = 49;
1322:            static final int LDAP_INSUFFICIENT_ACCESS_RIGHTS = 50;
1323:            static final int LDAP_BUSY = 51;
1324:            static final int LDAP_UNAVAILABLE = 52;
1325:            static final int LDAP_UNWILLING_TO_PERFORM = 53;
1326:            static final int LDAP_LOOP_DETECT = 54;
1327:            static final int LDAP_NAMING_VIOLATION = 64;
1328:            static final int LDAP_OBJECT_CLASS_VIOLATION = 65;
1329:            static final int LDAP_NOT_ALLOWED_ON_NON_LEAF = 66;
1330:            static final int LDAP_NOT_ALLOWED_ON_RDN = 67;
1331:            static final int LDAP_ENTRY_ALREADY_EXISTS = 68;
1332:            static final int LDAP_OBJECT_CLASS_MODS_PROHIBITED = 69;
1333:            static final int LDAP_AFFECTS_MULTIPLE_DSAS = 71; // LDAPv3
1334:            static final int LDAP_OTHER = 80;
1335:
1336:            static final String[] ldap_error_message = {
1337:                    "Success", // 0
1338:                    "Operations Error", // 1
1339:                    "Protocol Error", // 2
1340:                    "Timelimit Exceeded", // 3
1341:                    "Sizelimit Exceeded", // 4
1342:                    "Compare False", // 5
1343:                    "Compare True", // 6
1344:                    "Authentication Method Not Supported", // 7
1345:                    "Strong Authentication Required", // 8
1346:                    null,
1347:                    "Referral", // 10
1348:                    "Administrative Limit Exceeded", // 11
1349:                    "Unavailable Critical Extension", // 12
1350:                    "Confidentiality Required", // 13
1351:                    "SASL Bind In Progress", // 14
1352:                    null,
1353:                    "No Such Attribute", // 16
1354:                    "Undefined Attribute Type", // 17
1355:                    "Inappropriate Matching", // 18
1356:                    "Constraint Violation", // 19
1357:                    "Attribute Or Value Exists", // 20
1358:                    "Invalid Attribute Syntax", // 21
1359:                    null, null, null, null, null, null,
1360:                    null,
1361:                    null,
1362:                    null,
1363:                    null,
1364:                    "No Such Object", // 32
1365:                    "Alias Problem", // 33
1366:                    "Invalid DN Syntax", // 34
1367:                    null,
1368:                    "Alias Dereferencing Problem", // 36
1369:                    null, null, null, null, null, null, null, null, null, null,
1370:                    null,
1371:                    "Inappropriate Authentication", // 48
1372:                    "Invalid Credentials", // 49
1373:                    "Insufficient Access Rights", // 50
1374:                    "Busy", // 51
1375:                    "Unavailable", // 52
1376:                    "Unwilling To Perform", // 53
1377:                    "Loop Detect", // 54
1378:                    null, null, null, null, null, null, null, null, null,
1379:                    "Naming Violation", // 64
1380:                    "Object Class Violation", // 65
1381:                    "Not Allowed On Non-leaf", // 66
1382:                    "Not Allowed On RDN", // 67
1383:                    "Entry Already Exists", // 68
1384:                    "Object Class Modifications Prohibited", // 69
1385:                    null, "Affects Multiple DSAs", // 71
1386:                    null, null, null, null, null, null, null, null, "Other", // 80
1387:                    null, null, null, null, null, null, null, null, null, null };
1388:
1389:            /*
1390:             * Generate an error message from the LDAP error code and error diagnostic.
1391:             * The message format is:
1392:             *
1393:             *     "[LDAP: error code <errorCode> - <errorMessage>]"
1394:             *
1395:             * where <errorCode> is a numeric error code
1396:             * and <errorMessage> is a textual description of the error (if available)
1397:             *
1398:             */
1399:            static String getErrorMessage(int errorCode, String errorMessage) {
1400:
1401:                String message = "[LDAP: error code " + errorCode;
1402:
1403:                if ((errorMessage != null) && (errorMessage.length() != 0)) {
1404:
1405:                    // append error message from the server
1406:                    message = message + " - " + errorMessage + "]";
1407:
1408:                } else {
1409:
1410:                    // append built-in error message
1411:                    try {
1412:                        if (ldap_error_message[errorCode] != null) {
1413:                            message = message + " - "
1414:                                    + ldap_error_message[errorCode] + "]";
1415:                        }
1416:                    } catch (ArrayIndexOutOfBoundsException ex) {
1417:                        message = message + "]";
1418:                    }
1419:                }
1420:                return message;
1421:            }
1422:
1423:            ////////////////////////////////////////////////////////////////////////////
1424:            //
1425:            // Unsolicited notification support.
1426:            //
1427:            // An LdapClient maintains a list of LdapCtx that have registered
1428:            // for UnsolicitedNotifications. This is a list because a single
1429:            // LdapClient might be shared among multiple contexts.
1430:            //
1431:            // When addUnsolicited() is invoked, the LdapCtx is added to the list.
1432:            // 
1433:            // When Connection receives an unsolicited notification (msgid == 0),
1434:            // it invokes LdapClient.processUnsolicited(). processUnsolicited()
1435:            // parses the Extended Response. If there are registered listeners,
1436:            // LdapClient creates an UnsolicitedNotification from the response
1437:            // and informs each LdapCtx to fire an event for the notification.
1438:            // If it is a DISCONNECT notification, the connection is closed and a
1439:            // NamingExceptionEvent is fired to the listeners.
1440:            //
1441:            // When the connection is closed out-of-band like this, the next
1442:            // time a method is invoked on LdapClient, an IOException is thrown.
1443:            // 
1444:            // removeUnsolicited() is invoked to remove an LdapCtx from this client.
1445:            //
1446:            ////////////////////////////////////////////////////////////////////////////
1447:            private Vector unsolicited = new Vector(3);
1448:
1449:            void addUnsolicited(LdapCtx ctx) {
1450:                if (debug > 0) {
1451:                    System.err.println("LdapClient.addUnsolicited" + ctx);
1452:                }
1453:                unsolicited.addElement(ctx);
1454:            }
1455:
1456:            void removeUnsolicited(LdapCtx ctx) {
1457:                if (debug > 0) {
1458:                    System.err.println("LdapClient.removeUnsolicited" + ctx);
1459:                }
1460:                synchronized (unsolicited) {
1461:                    if (unsolicited.size() == 0) {
1462:                        return;
1463:                    }
1464:                    unsolicited.removeElement(ctx);
1465:                }
1466:            }
1467:
1468:            // NOTE: Cannot be synchronized because this is called asynchronously
1469:            // by the reader thread in Connection. Instead, sync on 'unsolicited' Vector.
1470:            void processUnsolicited(BerDecoder ber) {
1471:                if (debug > 0) {
1472:                    System.err.println("LdapClient.processUnsolicited");
1473:                }
1474:                synchronized (unsolicited) {
1475:                    try {
1476:                        // Parse the response
1477:                        LdapResult res = new LdapResult();
1478:
1479:                        ber.parseSeq(null); // init seq
1480:                        ber.parseInt(); // msg id; should be 0; ignored
1481:                        if (ber.parseByte() != LDAP_REP_EXTENSION) {
1482:                            throw new IOException(
1483:                                    "Unsolicited Notification must be an Extended Response");
1484:                        }
1485:                        ber.parseLength();
1486:                        parseExtResponse(ber, res);
1487:
1488:                        if (DISCONNECT_OID.equals(res.extensionId)) {
1489:                            // force closing of connection
1490:                            forceClose(pooled);
1491:                        }
1492:
1493:                        if (unsolicited.size() > 0) {
1494:                            // Create an UnsolicitedNotification using the parsed data
1495:                            // Need a 'ctx' object because we want to use the context's
1496:                            // list of provider control factories.
1497:                            UnsolicitedNotification notice = new UnsolicitedResponseImpl(
1498:                                    res.extensionId,
1499:                                    res.extensionValue,
1500:                                    res.referrals,
1501:                                    res.status,
1502:                                    res.errorMessage,
1503:                                    res.matchedDN,
1504:                                    (res.resControls != null) ? ((LdapCtx) unsolicited
1505:                                            .elementAt(0))
1506:                                            .convertControls(res.resControls)
1507:                                            : null);
1508:
1509:                            // Fire UnsolicitedNotification events to listeners
1510:                            notifyUnsolicited(notice);
1511:
1512:                            // If "disconnect" notification, 
1513:                            // notify unsolicited listeners via NamingException
1514:                            if (DISCONNECT_OID.equals(res.extensionId)) {
1515:                                notifyUnsolicited(new CommunicationException(
1516:                                        "Connection closed"));
1517:                            }
1518:                        }
1519:                    } catch (IOException e) {
1520:                        if (unsolicited.size() == 0)
1521:                            return; // no one registered; ignore
1522:
1523:                        NamingException ne = new CommunicationException(
1524:                                "Problem parsing unsolicited notification");
1525:                        ne.setRootCause(e);
1526:
1527:                        notifyUnsolicited(ne);
1528:
1529:                    } catch (NamingException e) {
1530:                        notifyUnsolicited(e);
1531:                    }
1532:                }
1533:            }
1534:
1535:            private void notifyUnsolicited(Object e) {
1536:                for (int i = 0; i < unsolicited.size(); i++) {
1537:                    ((LdapCtx) unsolicited.elementAt(i)).fireUnsolicited(e);
1538:                }
1539:                if (e instanceof  NamingException) {
1540:                    unsolicited.setSize(0); // no more listeners after exception
1541:                }
1542:            }
1543:
1544:            private void ensureOpen() throws IOException {
1545:                if (conn == null || !conn.useable) {
1546:                    if (conn != null && conn.closureReason != null) {
1547:                        throw conn.closureReason;
1548:                    } else {
1549:                        throw new IOException("connection closed");
1550:                    }
1551:                }
1552:            }
1553:
1554:            // package private (used by LdapCtx)
1555:            static LdapClient getInstance(boolean usePool, String hostname,
1556:                    int port, String factory, int connectTimeout,
1557:                    int readTimeout, OutputStream trace, int version,
1558:                    String authMechanism, Control[] ctls, String protocol,
1559:                    String user, Object passwd, Hashtable env)
1560:                    throws NamingException {
1561:
1562:                if (usePool) {
1563:                    if (LdapPoolManager.isPoolingAllowed(factory, trace,
1564:                            authMechanism, protocol, env)) {
1565:                        LdapClient answer = LdapPoolManager.getLdapClient(
1566:                                hostname, port, factory, connectTimeout,
1567:                                readTimeout, trace, version, authMechanism,
1568:                                ctls, protocol, user, passwd, env);
1569:                        answer.referenceCount = 1; // always one when starting out
1570:                        return answer;
1571:                    }
1572:                }
1573:                return new LdapClient(hostname, port, factory, connectTimeout,
1574:                        readTimeout, trace, null);
1575:            }
1576:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.