001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.protocols.ldap;
028    import org.opends.messages.Message;
029    
030    
031    
032    import java.util.ArrayList;
033    
034    import org.opends.server.protocols.asn1.ASN1Element;
035    import org.opends.server.protocols.asn1.ASN1Integer;
036    import org.opends.server.protocols.asn1.ASN1OctetString;
037    import org.opends.server.protocols.asn1.ASN1Sequence;
038    import org.opends.server.types.AuthenticationType;
039    import org.opends.server.types.DebugLogLevel;
040    import org.opends.server.types.LDAPException;
041    
042    import static org.opends.server.loggers.debug.DebugLogger.*;
043    import org.opends.server.loggers.debug.DebugTracer;
044    import static org.opends.messages.ProtocolMessages.*;
045    import static org.opends.server.protocols.ldap.LDAPConstants.*;
046    import static org.opends.server.protocols.ldap.LDAPResultCode.*;
047    import static org.opends.server.util.ServerConstants.*;
048    
049    
050    
051    /**
052     * This class defines the structures and methods for an LDAP bind request
053     * protocol op, which is used to authenticate a user to the Directory Server.
054     */
055    public class BindRequestProtocolOp
056           extends ProtocolOp
057    {
058      /**
059       * The tracer object for the debug logger.
060       */
061      private static final DebugTracer TRACER = getTracer();
062    
063      // The bind DN for this request.
064      private ASN1OctetString dn;
065    
066      // The SASL credentials for this request.
067      private ASN1OctetString saslCredentials;
068    
069      // The simple authentication password for this request.
070      private ASN1OctetString simplePassword;
071    
072      // The authentication type for this request.
073      private AuthenticationType authenticationType;
074    
075      // The protocol version for this bind request.
076      private int protocolVersion;
077    
078      // The SASL mechanism for this request.
079      private String saslMechanism;
080    
081    
082    
083      /**
084       * Creates a new bind request protocol op to perform simple authentication
085       * with the provided DN and password.
086       *
087       * @param  dn               The DN for this bind request.
088       * @param  protocolVersion  The LDAP protocol version for this bind request.
089       * @param  simplePassword   The password for this bind request.
090       */
091      public BindRequestProtocolOp(ASN1OctetString dn, int protocolVersion,
092                                   ASN1OctetString simplePassword)
093      {
094        this.dn              = dn;
095        this.protocolVersion = protocolVersion;
096        this.simplePassword  = simplePassword;
097    
098        authenticationType = AuthenticationType.SIMPLE;
099        saslMechanism      = null;
100        saslCredentials    = null;
101      }
102    
103    
104    
105      /**
106       * Creates a new bind request protocol op to perform SASL authentication with
107       * the provided information.
108       *
109       * @param  dn               The DN for this bind request.
110       * @param  saslMechanism    The SASL mechanism for this bind request.
111       * @param  saslCredentials  The SASL credentials for this bind request.
112       */
113      public BindRequestProtocolOp(ASN1OctetString dn, String saslMechanism,
114                                   ASN1OctetString saslCredentials)
115      {
116        this.dn              = dn;
117        this.saslMechanism   = saslMechanism;
118        this.saslCredentials = saslCredentials;
119    
120        authenticationType = AuthenticationType.SASL;
121        protocolVersion    = 3;
122        simplePassword     = null;
123      }
124    
125    
126    
127      /**
128       * Creates a new bind request protocol op to perform SASL authentication with
129       * the provided information.
130       *
131       * @param  dn                  The DN for this bind request.
132       * @param  protocolVersion     The protocol version for this bind request.
133       * @param  authenticationType  The authentication type for this bind request.
134       * @param  simplePassword      The password for this bind request.
135       * @param  saslMechanism       The SASL mechanism for this bind request.
136       * @param  saslCredentials     The SASL credentials for this bind request.
137       */
138      private BindRequestProtocolOp(ASN1OctetString dn, int protocolVersion,
139                                    AuthenticationType authenticationType,
140                                    ASN1OctetString simplePassword,
141                                    String saslMechanism,
142                                    ASN1OctetString saslCredentials)
143      {
144        this.dn                 = dn;
145        this.protocolVersion    = protocolVersion;
146        this.authenticationType = authenticationType;
147        this.simplePassword     = simplePassword;
148        this.saslMechanism      = saslMechanism;
149        this.saslCredentials    = saslCredentials;
150      }
151    
152    
153    
154      /**
155       * Retrieves the DN for this bind request.
156       *
157       * @return  The DN for this bind request.
158       */
159      public ASN1OctetString getDN()
160      {
161        return dn;
162      }
163    
164    
165    
166      /**
167       * Specifies the DN for this bind request.
168       *
169       * @param  dn  The DN for this bind request.
170       */
171      public void setDN(ASN1OctetString dn)
172      {
173        this.dn = dn;
174      }
175    
176    
177    
178      /**
179       * Retrieves the protocol version for this bind request.
180       *
181       * @return  The protocol version for this bind request.
182       */
183      public int getProtocolVersion()
184      {
185        return protocolVersion;
186      }
187    
188    
189    
190      /**
191       * Specifies the protocol version for this bind request.
192       *
193       * @param  protocolVersion  The protocol version for this bind request.
194       */
195      public void setProtocolVersion(int protocolVersion)
196      {
197        this.protocolVersion = protocolVersion;
198      }
199    
200    
201    
202      /**
203       * Retrieves the authentication type for this bind request.
204       *
205       * @return  The authentication type for this bind request.
206       */
207      public AuthenticationType getAuthenticationType()
208      {
209        return authenticationType;
210      }
211    
212    
213    
214      /**
215       * Retrieves the simple authentication password for this bind request.
216       *
217       * @return  The simple authentication password for this bind request, or
218       *          <CODE>null</CODE> if this is a SASL bind request.
219       */
220      public ASN1OctetString getSimplePassword()
221      {
222        return simplePassword;
223      }
224    
225    
226    
227      /**
228       * Indicates that this bind request should use simple authentication with the
229       * provided password.
230       *
231       * @param  simplePassword  The simple authentication password for this bind
232       *                         request.
233       */
234      public void setSimplePassword(ASN1OctetString simplePassword)
235      {
236        this.simplePassword = simplePassword;
237        authenticationType  = AuthenticationType.SIMPLE;
238        saslMechanism       = null;
239        saslCredentials     = null;
240      }
241    
242    
243    
244      /**
245       * Retrieves the SASL mechanism for this bind request.
246       *
247       * @return  The SASL mechanism for this bind request, or <CODE>null</CODE> if
248       *          this is a simple bind request.
249       */
250      public String getSASLMechanism()
251      {
252        return saslMechanism;
253      }
254    
255    
256    
257      /**
258       * Retrieves the SASL credentials for this bind request.
259       *
260       * @return  The SASL credentials for this bind request, or <CODE>null</CODE>
261       *          if there are none or if this is a simple bind request.
262       */
263      public ASN1OctetString getSASLCredentials()
264      {
265        return saslCredentials;
266      }
267    
268    
269    
270      /**
271       * Indicates that this bind request should use SASL authentication with the
272       * provided information.
273       *
274       * @param  saslMechanism    The SASL mechanism for this bind request.
275       * @param  saslCredentials  The SASL credentials for this bind request.
276       */
277      public void setSASLAuthenticationInfo(String saslMechanism,
278                                            ASN1OctetString saslCredentials)
279      {
280        this.saslMechanism   = saslMechanism;
281        this.saslCredentials = saslCredentials;
282        authenticationType   = AuthenticationType.SASL;
283        simplePassword       = null;
284      }
285    
286    
287    
288    
289      /**
290       * Retrieves the BER type for this protocol op.
291       *
292       * @return  The BER type for this protocol op.
293       */
294      public byte getType()
295      {
296        return OP_TYPE_BIND_REQUEST;
297      }
298    
299    
300    
301      /**
302       * Retrieves the name for this protocol op type.
303       *
304       * @return  The name for this protocol op type.
305       */
306      public String getProtocolOpName()
307      {
308        return "Bind Request";
309      }
310    
311    
312    
313      /**
314       * Encodes this protocol op to an ASN.1 element suitable for including in an
315       * LDAP message.
316       *
317       * @return  The ASN.1 element containing the encoded protocol op.
318       */
319      public ASN1Element encode()
320      {
321        ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
322    
323        elements.add(new ASN1Integer(protocolVersion));
324        elements.add(dn);
325    
326        if (authenticationType == AuthenticationType.SIMPLE)
327        {
328          simplePassword.setType(TYPE_AUTHENTICATION_SIMPLE);
329          elements.add(simplePassword);
330        }
331        else
332        {
333          ArrayList<ASN1Element> saslElements = new ArrayList<ASN1Element>(2);
334          saslElements.add(new ASN1OctetString(saslMechanism));
335          if (saslCredentials != null)
336          {
337            saslElements.add(saslCredentials);
338          }
339    
340          elements.add(new ASN1Sequence(TYPE_AUTHENTICATION_SASL, saslElements));
341        }
342    
343        return new ASN1Sequence(OP_TYPE_BIND_REQUEST, elements);
344      }
345    
346    
347    
348      /**
349       * Decodes the provided ASN.1 element as an LDAP bind request protocol op.
350       *
351       * @param  element  The ASN.1 element to decode.
352       *
353       * @return  The decoded LDAP bind request protocol op.
354       *
355       * @throws  LDAPException  If a problem occurs while trying to decode the
356       *                         provided ASN.1 element as an LDAP bind request.
357       */
358      public static BindRequestProtocolOp decodeBindRequest(ASN1Element element)
359             throws LDAPException
360      {
361        ArrayList<ASN1Element> elements;
362        try
363        {
364          elements = element.decodeAsSequence().elements();
365        }
366        catch (Exception e)
367        {
368          if (debugEnabled())
369          {
370            TRACER.debugCaught(DebugLogLevel.ERROR, e);
371          }
372    
373          Message message =
374              ERR_LDAP_BIND_REQUEST_DECODE_SEQUENCE.get(String.valueOf(e));
375          throw new LDAPException(PROTOCOL_ERROR, message, e);
376        }
377    
378    
379        int numElements = elements.size();
380        if (numElements != 3)
381        {
382          Message message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_ELEMENT_COUNT.get(
383              numElements);
384          throw new LDAPException(PROTOCOL_ERROR, message);
385        }
386    
387    
388        int protocolVersion;
389        try
390        {
391          protocolVersion = elements.get(0).decodeAsInteger().intValue();
392        }
393        catch (Exception e)
394        {
395          if (debugEnabled())
396          {
397            TRACER.debugCaught(DebugLogLevel.ERROR, e);
398          }
399    
400          Message message =
401              ERR_LDAP_BIND_REQUEST_DECODE_VERSION.get(String.valueOf(e));
402          throw new LDAPException(PROTOCOL_ERROR, message, e);
403        }
404    
405    
406        ASN1OctetString dn;
407        try
408        {
409          dn = elements.get(1).decodeAsOctetString();
410        }
411        catch (Exception e)
412        {
413          if (debugEnabled())
414          {
415            TRACER.debugCaught(DebugLogLevel.ERROR, e);
416          }
417    
418          Message message = ERR_LDAP_BIND_REQUEST_DECODE_DN.get(String.valueOf(e));
419          throw new LDAPException(PROTOCOL_ERROR, message, e);
420        }
421    
422    
423        AuthenticationType authenticationType;
424        ASN1OctetString    simplePassword  = null;
425        String             saslMechanism   = null;
426        ASN1OctetString    saslCredentials = null;
427        try
428        {
429          element = elements.get(2);
430          switch (element.getType())
431          {
432            case TYPE_AUTHENTICATION_SIMPLE:
433              authenticationType = AuthenticationType.SIMPLE;
434    
435              try
436              {
437                simplePassword = element.decodeAsOctetString();
438              }
439              catch (Exception e)
440              {
441                Message message =
442                    ERR_LDAP_BIND_REQUEST_DECODE_PASSWORD.get(String.valueOf(e));
443                throw new LDAPException(PROTOCOL_ERROR, message, e);
444              }
445    
446              break;
447            case TYPE_AUTHENTICATION_SASL:
448              authenticationType = AuthenticationType.SASL;
449    
450              try
451              {
452                elements = element.decodeAsSequence().elements();
453    
454                saslMechanism = elements.get(0).decodeAsOctetString().stringValue();
455                if (elements.size() == 2)
456                {
457                  saslCredentials = elements.get(1).decodeAsOctetString();
458                }
459              }
460              catch (Exception e)
461              {
462                Message message =
463                    ERR_LDAP_BIND_REQUEST_DECODE_SASL_INFO.get(String.valueOf(e));
464                throw new LDAPException(PROTOCOL_ERROR, message, e);
465              }
466    
467              break;
468            default:
469              Message message = ERR_LDAP_BIND_REQUEST_DECODE_INVALID_CRED_TYPE.get(
470                  element.getType());
471              throw new LDAPException(AUTH_METHOD_NOT_SUPPORTED, message);
472          }
473        }
474        catch (LDAPException le)
475        {
476          throw le;
477        }
478        catch (Exception e)
479        {
480          if (debugEnabled())
481          {
482            TRACER.debugCaught(DebugLogLevel.ERROR, e);
483          }
484    
485          Message message =
486              ERR_LDAP_BIND_REQUEST_DECODE_CREDENTIALS.get(String.valueOf(e));
487          throw new LDAPException(PROTOCOL_ERROR, message, e);
488        }
489    
490    
491        return new BindRequestProtocolOp(dn, protocolVersion, authenticationType,
492                                         simplePassword, saslMechanism,
493                                         saslCredentials);
494      }
495    
496    
497      /**
498       * Appends a string representation of this LDAP protocol op to the provided
499       * buffer.
500       *
501       * @param  buffer  The buffer to which the string should be appended.
502       */
503      public void toString(StringBuilder buffer)
504      {
505        buffer.append("BindRequest(version=");
506        buffer.append(protocolVersion);
507        buffer.append(", dn=");
508    
509        if (dn != null)
510        {
511          dn.toString(buffer);
512        }
513    
514        if (authenticationType == AuthenticationType.SIMPLE)
515        {
516          buffer.append(", password=");
517          simplePassword.toString(buffer);
518        }
519        else
520        {
521          buffer.append(", saslMechanism=");
522          buffer.append(saslMechanism);
523    
524          if (saslCredentials != null)
525          {
526            buffer.append(", saslCredentials=");
527            saslCredentials.toString(buffer);
528          }
529        }
530    
531        buffer.append(")");
532      }
533    
534    
535    
536      /**
537       * Appends a multi-line string representation of this LDAP protocol op to the
538       * provided buffer.
539       *
540       * @param  buffer  The buffer to which the information should be appended.
541       * @param  indent  The number of spaces from the margin that the lines should
542       *                 be indented.
543       */
544      public void toString(StringBuilder buffer, int indent)
545      {
546        StringBuilder indentBuf = new StringBuilder(indent);
547        for (int i=0 ; i < indent; i++)
548        {
549          indentBuf.append(' ');
550        }
551    
552        buffer.append(indentBuf);
553        buffer.append("Bind Request");
554        buffer.append(EOL);
555    
556        buffer.append(indentBuf);
557        buffer.append("  Protocol Version:  ");
558        buffer.append(protocolVersion);
559        buffer.append(EOL);
560    
561        buffer.append(indentBuf);
562        buffer.append("  DN:  ");
563        if (dn != null)
564        {
565          dn.toString(buffer);
566        }
567        buffer.append(EOL);
568    
569        if (authenticationType == AuthenticationType.SIMPLE)
570        {
571          buffer.append(indentBuf);
572          buffer.append("  Simple Password:  ");
573          buffer.append(String.valueOf(simplePassword));
574          buffer.append(EOL);
575        }
576        else
577        {
578          buffer.append(indentBuf);
579          buffer.append("  SASL Mechanism:  ");
580          buffer.append(saslMechanism);
581          buffer.append(EOL);
582    
583          if (saslCredentials != null)
584          {
585            buffer.append(indentBuf);
586            buffer.append("  SASL Credentials:");
587            buffer.append(EOL);
588            saslCredentials.toString(buffer, indent+4);
589          }
590        }
591      }
592    }
593