001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk;
022
023
024
025import com.unboundid.asn1.ASN1OctetString;
026import com.unboundid.util.NotMutable;
027import com.unboundid.util.StaticUtils;
028import com.unboundid.util.ThreadSafety;
029import com.unboundid.util.ThreadSafetyLevel;
030
031
032
033/**
034 * This class provides a SASL EXTERNAL bind request implementation as described
035 * in <A HREF="http://www.ietf.org/rfc/rfc4422.txt">RFC 4422</A>.  The
036 * EXTERNAL mechanism is used to authenticate using information that is
037 * available outside of the LDAP layer (e.g., a certificate presented by the
038 * client during SSL or StartTLS negotiation).
039 * <BR><BR>
040 * <H2>Example</H2>
041 * The following example demonstrates the process for performing an EXTERNAL
042 * bind against a directory server:
043 * <PRE>
044 * EXTERNALBindRequest bindRequest = new EXTERNALBindRequest("");
045 * BindResult bindResult;
046 * try
047 * {
048 *   bindResult = connection.bind(bindRequest);
049 *   // If we get here, then the bind was successful.
050 * }
051 * catch (LDAPException le)
052 * {
053 *   // The bind failed for some reason.
054 *   bindResult = new BindResult(le.toLDAPResult());
055 *   ResultCode resultCode = le.getResultCode();
056 *   String errorMessageFromServer = le.getDiagnosticMessage();
057 * }
058 * </PRE>
059 */
060@NotMutable()
061@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
062public final class EXTERNALBindRequest
063       extends SASLBindRequest
064{
065  /**
066   * The name for the EXTERNAL SASL mechanism.
067   */
068  public static final String EXTERNAL_MECHANISM_NAME = "EXTERNAL";
069
070
071
072  /**
073   * The serial version UID for this serializable class.
074   */
075  private static final long serialVersionUID = 7520760039662616663L;
076
077
078
079  // The message ID from the last LDAP message sent from this request.
080  private int messageID = -1;
081
082  // The authorization ID to send to the server in the bind request.  It may be
083  // null, empty, or non-empty.
084  private final String authzID;
085
086
087
088  /**
089   * Creates a new SASL EXTERNAL bind request with no authorization ID and no
090   * controls.
091   */
092  public EXTERNALBindRequest()
093  {
094    this(null, StaticUtils.NO_CONTROLS);
095  }
096
097
098
099  /**
100   * Creates a new SASL EXTERNAL bind request with the specified authorization
101   * ID and no controls.
102   *
103   * @param  authzID  The authorization ID to use for the bind request.  It may
104   *                  be {@code null} if the client should not send any
105   *                  authorization ID at all (which may be required by some
106   *                  servers).  It may be an empty string if the server should
107   *                  determine the authorization identity from what it knows
108   *                  about the client (e.g., a client certificate).  It may be
109   *                  a non-empty string if the authorization identity should
110   *                  be different from the authentication identity.
111   */
112  public EXTERNALBindRequest(final String authzID)
113  {
114    this(authzID, StaticUtils.NO_CONTROLS);
115  }
116
117
118
119
120  /**
121   * Creates a new SASL EXTERNAL bind request with the provided set of controls.
122   *
123   * @param  controls  The set of controls to include in this SASL EXTERNAL
124   *                   bind request.
125   */
126  public EXTERNALBindRequest(final Control... controls)
127  {
128    this(null, controls);
129  }
130
131
132
133
134  /**
135   * Creates a new SASL EXTERNAL bind request with the provided set of controls.
136   *
137   *
138   * @param  authzID   The authorization ID to use for the bind request.  It may
139   *                   be {@code null} if the client should not send any
140   *                   authorization ID at all (which may be required by some
141   *                   servers).  It may be an empty string if the server should
142   *                   determine the authorization identity from what it knows
143   *                   about the client (e.g., a client certificate).  It may be
144   *                   a non-empty string if the authorization identity should
145   *                   be different from the authentication identity.
146   * @param  controls  The set of controls to include in this SASL EXTERNAL
147   *                   bind request.
148   */
149  public EXTERNALBindRequest(final String authzID, final Control... controls)
150  {
151    super(controls);
152
153    this.authzID = authzID;
154  }
155
156
157
158  /**
159   * Retrieves the authorization ID that should be included in the bind request,
160   * if any.
161   *
162   * @return  The authorization ID that should be included in the bind request,
163   *          or {@code null} if the bind request should be sent without an
164   *          authorization ID (which is a form that some servers require).  It
165   *          may be an empty string if the authorization identity should be the
166   *          same as the authentication identity and should be determined from
167   *          what the server already knows about the client.
168   */
169  public String getAuthorizationID()
170  {
171    return authzID;
172  }
173
174
175
176  /**
177   * {@inheritDoc}
178   */
179  @Override()
180  public String getSASLMechanismName()
181  {
182    return EXTERNAL_MECHANISM_NAME;
183  }
184
185
186
187  /**
188   * Sends this bind request to the target server over the provided connection
189   * and returns the corresponding response.
190   *
191   * @param  connection  The connection to use to send this bind request to the
192   *                     server and read the associated response.
193   * @param  depth       The current referral depth for this request.  It should
194   *                     always be one for the initial request, and should only
195   *                     be incremented when following referrals.
196   *
197   * @return  The bind response read from the server.
198   *
199   * @throws  LDAPException  If a problem occurs while sending the request or
200   *                         reading the response.
201   */
202  @Override()
203  protected BindResult process(final LDAPConnection connection, final int depth)
204            throws LDAPException
205  {
206    // Create the LDAP message.
207    messageID = connection.nextMessageID();
208
209    final ASN1OctetString creds;
210    if (authzID == null)
211    {
212      creds = null;
213    }
214    else
215    {
216      creds = new ASN1OctetString(authzID);
217    }
218
219    return sendBindRequest(connection, "", creds, getControls(),
220                           getResponseTimeoutMillis(connection));
221  }
222
223
224
225  /**
226   * {@inheritDoc}
227   */
228  @Override()
229  public EXTERNALBindRequest getRebindRequest(final String host, final int port)
230  {
231    return new EXTERNALBindRequest(authzID, getControls());
232  }
233
234
235
236  /**
237   * {@inheritDoc}
238   */
239  @Override()
240  public int getLastMessageID()
241  {
242    return messageID;
243  }
244
245
246
247  /**
248   * {@inheritDoc}
249   */
250  @Override()
251  public EXTERNALBindRequest duplicate()
252  {
253    return duplicate(getControls());
254  }
255
256
257
258  /**
259   * {@inheritDoc}
260   */
261  @Override()
262  public EXTERNALBindRequest duplicate(final Control[] controls)
263  {
264    final EXTERNALBindRequest bindRequest =
265         new EXTERNALBindRequest(authzID, controls);
266    bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
267    return bindRequest;
268  }
269
270
271
272  /**
273   * {@inheritDoc}
274   */
275  @Override()
276  public void toString(final StringBuilder buffer)
277  {
278    buffer.append("EXTERNALBindRequest(");
279
280    boolean added = false;
281    if (authzID != null)
282    {
283      buffer.append("authzID='");
284      buffer.append(authzID);
285      buffer.append('\'');
286      added = true;
287    }
288
289    final Control[] controls = getControls();
290    if (controls.length > 0)
291    {
292      if (added)
293      {
294        buffer.append(", ");
295      }
296
297      buffer.append("controls={");
298      for (int i=0; i < controls.length; i++)
299      {
300        if (i > 0)
301        {
302          buffer.append(", ");
303        }
304
305        buffer.append(controls[i]);
306      }
307      buffer.append('}');
308    }
309
310    buffer.append(')');
311  }
312}