001    /*
002     * Copyright 2007-2013 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2013 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     */
021    package com.unboundid.ldap.sdk;
022    
023    
024    
025    import com.unboundid.asn1.ASN1OctetString;
026    import com.unboundid.util.NotMutable;
027    import com.unboundid.util.StaticUtils;
028    import com.unboundid.util.ThreadSafety;
029    import 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     *   try
045     *   {
046     *     BindResult bindResult = connection.bind(new EXTERNALBindRequest());
047     *     // If we get here, then the bind was successful.
048     *   }
049     *   catch (LDAPException le)
050     *   {
051     *     // The bind failed for some reason.
052     *   }
053     * </PRE>
054     */
055    @NotMutable()
056    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
057    public final class EXTERNALBindRequest
058           extends SASLBindRequest
059    {
060      /**
061       * The name for the EXTERNAL SASL mechanism.
062       */
063      public static final String EXTERNAL_MECHANISM_NAME = "EXTERNAL";
064    
065    
066    
067      /**
068       * The serial version UID for this serializable class.
069       */
070      private static final long serialVersionUID = 7520760039662616663L;
071    
072    
073    
074      // The message ID from the last LDAP message sent from this request.
075      private int messageID = -1;
076    
077      // The authorization ID to send to the server in the bind request.  It may be
078      // null, empty, or non-empty.
079      private final String authzID;
080    
081    
082    
083      /**
084       * Creates a new SASL EXTERNAL bind request with no authorization ID and no
085       * controls.
086       */
087      public EXTERNALBindRequest()
088      {
089        this(null, StaticUtils.NO_CONTROLS);
090      }
091    
092    
093    
094      /**
095       * Creates a new SASL EXTERNAL bind request with the specified authorization
096       * ID and no controls.
097       *
098       * @param  authzID  The authorization ID to use for the bind request.  It may
099       *                  be {@code null} if the client should not send any
100       *                  authorization ID at all (which may be required by some
101       *                  servers).  It may be an empty string if the server should
102       *                  determine the authorization identity from what it knows
103       *                  about the client (e.g., a client certificate).  It may be
104       *                  a non-empty string if the authorization identity should
105       *                  be different from the authentication identity.
106       */
107      public EXTERNALBindRequest(final String authzID)
108      {
109        this(authzID, StaticUtils.NO_CONTROLS);
110      }
111    
112    
113    
114    
115      /**
116       * Creates a new SASL EXTERNAL bind request with the provided set of controls.
117       *
118       * @param  controls  The set of controls to include in this SASL EXTERNAL
119       *                   bind request.
120       */
121      public EXTERNALBindRequest(final Control... controls)
122      {
123        this(null, controls);
124      }
125    
126    
127    
128    
129      /**
130       * Creates a new SASL EXTERNAL bind request with the provided set of controls.
131       *
132       *
133       * @param  authzID   The authorization ID to use for the bind request.  It may
134       *                   be {@code null} if the client should not send any
135       *                   authorization ID at all (which may be required by some
136       *                   servers).  It may be an empty string if the server should
137       *                   determine the authorization identity from what it knows
138       *                   about the client (e.g., a client certificate).  It may be
139       *                   a non-empty string if the authorization identity should
140       *                   be different from the authentication identity.
141       * @param  controls  The set of controls to include in this SASL EXTERNAL
142       *                   bind request.
143       */
144      public EXTERNALBindRequest(final String authzID, final Control... controls)
145      {
146        super(controls);
147    
148        this.authzID = authzID;
149      }
150    
151    
152    
153      /**
154       * Retrieves the authorization ID that should be included in the bind request,
155       * if any.
156       *
157       * @return  The authorization ID that should be included in the bind request,
158       *          or {@code null} if the bind request should be sent without an
159       *          authorization ID (which is a form that some servers require).  It
160       *          may be an empty string if the authorization identity should be the
161       *          same as the authentication identity and should be determined from
162       *          what the server already knows about the client.
163       */
164      public String getAuthorizationID()
165      {
166        return authzID;
167      }
168    
169    
170    
171      /**
172       * {@inheritDoc}
173       */
174      @Override()
175      public String getSASLMechanismName()
176      {
177        return EXTERNAL_MECHANISM_NAME;
178      }
179    
180    
181    
182      /**
183       * Sends this bind request to the target server over the provided connection
184       * and returns the corresponding response.
185       *
186       * @param  connection  The connection to use to send this bind request to the
187       *                     server and read the associated response.
188       * @param  depth       The current referral depth for this request.  It should
189       *                     always be one for the initial request, and should only
190       *                     be incremented when following referrals.
191       *
192       * @return  The bind response read from the server.
193       *
194       * @throws  LDAPException  If a problem occurs while sending the request or
195       *                         reading the response.
196       */
197      @Override()
198      protected BindResult process(final LDAPConnection connection, final int depth)
199                throws LDAPException
200      {
201        // Create the LDAP message.
202        messageID = connection.nextMessageID();
203    
204        final ASN1OctetString creds;
205        if (authzID == null)
206        {
207          creds = null;
208        }
209        else
210        {
211          creds = new ASN1OctetString(authzID);
212        }
213    
214        return sendBindRequest(connection, "", creds, getControls(),
215                               getResponseTimeoutMillis(connection));
216      }
217    
218    
219    
220      /**
221       * {@inheritDoc}
222       */
223      @Override()
224      public EXTERNALBindRequest getRebindRequest(final String host, final int port)
225      {
226        return new EXTERNALBindRequest(authzID, getControls());
227      }
228    
229    
230    
231      /**
232       * {@inheritDoc}
233       */
234      @Override()
235      public int getLastMessageID()
236      {
237        return messageID;
238      }
239    
240    
241    
242      /**
243       * {@inheritDoc}
244       */
245      @Override()
246      public EXTERNALBindRequest duplicate()
247      {
248        return duplicate(getControls());
249      }
250    
251    
252    
253      /**
254       * {@inheritDoc}
255       */
256      @Override()
257      public EXTERNALBindRequest duplicate(final Control[] controls)
258      {
259        final EXTERNALBindRequest bindRequest =
260             new EXTERNALBindRequest(authzID, controls);
261        bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
262        return bindRequest;
263      }
264    
265    
266    
267      /**
268       * {@inheritDoc}
269       */
270      @Override()
271      public void toString(final StringBuilder buffer)
272      {
273        buffer.append("EXTERNALBindRequest(");
274    
275        boolean added = false;
276        if (authzID != null)
277        {
278          buffer.append("authzID='");
279          buffer.append(authzID);
280          buffer.append('\'');
281          added = true;
282        }
283    
284        final Control[] controls = getControls();
285        if (controls.length > 0)
286        {
287          if (added)
288          {
289            buffer.append(", ");
290          }
291    
292          buffer.append("controls={");
293          for (int i=0; i < controls.length; i++)
294          {
295            if (i > 0)
296            {
297              buffer.append(", ");
298            }
299    
300            buffer.append(controls[i]);
301          }
302          buffer.append('}');
303        }
304    
305        buffer.append(')');
306      }
307    }