001    /*
002     * Copyright 2007-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 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 java.util.ArrayList;
026    import java.util.List;
027    
028    import com.unboundid.asn1.ASN1OctetString;
029    import com.unboundid.util.NotMutable;
030    import com.unboundid.util.ThreadSafety;
031    import com.unboundid.util.ThreadSafetyLevel;
032    
033    
034    
035    /**
036     * This class provides a SASL ANONYMOUS bind request implementation as described
037     * in <A HREF="http://www.ietf.org/rfc/rfc4505.txt">RFC 4505</A>.  Binding with
038     * The ANONYMOUS SASL mechanism is essentially equivalent to using an anonymous
039     * simple bind (i.e., a simple bind with an empty password), although the SASL
040     * ANONYMOUS mechanism does provide the ability to include additional trace
041     * information with the request that may be logged or otherwise handled by
042     * the server.
043     * <BR><BR>
044     * <H2>Example</H2>
045     * The following example demonstrates the process for performing an ANONYMOUS
046     * bind, including a trace string of "Demo Application" against a directory
047     * server:
048     * <PRE>
049     * ANONYMOUSBindRequest bindRequest =
050     *      new ANONYMOUSBindRequest("Demo Application");
051     * BindResult bindResult;
052     * try
053     * {
054     *   bindResult = connection.bind(bindRequest);
055     *   // If we get here, then the bind was successful.
056     * }
057     * catch (LDAPException le)
058     * {
059     *   // The bind failed for some reason.
060     *   bindResult = new BindResult(le.toLDAPResult());
061     *   ResultCode resultCode = le.getResultCode();
062     *   String errorMessageFromServer = le.getDiagnosticMessage();
063     * }
064     * </PRE>
065     */
066    @NotMutable()
067    @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
068    public final class ANONYMOUSBindRequest
069           extends SASLBindRequest
070    {
071      /**
072       * The name for the ANONYMOUS SASL mechanism.
073       */
074      public static final String ANONYMOUS_MECHANISM_NAME = "ANONYMOUS";
075    
076    
077    
078      /**
079       * The serial version UID for this serializable class.
080       */
081      private static final long serialVersionUID = 4259102841471750866L;
082    
083    
084    
085      // The trace string that should be included in the bind request, if available.
086      private final String traceString;
087    
088    
089    
090      /**
091       * Creates a new SASL ANONYMOUS bind request with no trace string and no
092       * controls.
093       */
094      public ANONYMOUSBindRequest()
095      {
096        this(null, NO_CONTROLS);
097      }
098    
099    
100    
101      /**
102       * Creates a new SASL ANONYMOUS bind request with the provided trace string
103       * and no controls.
104       *
105       * @param  traceString  The trace string to include in the bind request, or
106       *                      {@code null} if no trace string is to be provided.
107       */
108      public ANONYMOUSBindRequest(final String traceString)
109      {
110        this(traceString, NO_CONTROLS);
111      }
112    
113    
114    
115      /**
116       * Creates a new SASL ANONYMOUS bind request with the provided set of controls
117       * and no trace string.
118       *
119       * @param  controls     The set of controls to include in the request.
120       */
121      public ANONYMOUSBindRequest(final Control... controls)
122      {
123        this(null, controls);
124      }
125    
126    
127    
128      /**
129       * Creates a new SASL ANONYMOUS bind request with the provided trace string
130       * and controls.
131       *
132       * @param  traceString  The trace string to include in the bind request, or
133       *                      {@code null} if no trace string is to be provided.
134       * @param  controls     The set of controls to include in the request.
135       */
136      public ANONYMOUSBindRequest(final String traceString,
137                                  final Control... controls)
138      {
139        super(controls);
140    
141        this.traceString = traceString;
142      }
143    
144    
145    
146      /**
147       * {@inheritDoc}
148       */
149      @Override()
150      public String getSASLMechanismName()
151      {
152        return ANONYMOUS_MECHANISM_NAME;
153      }
154    
155    
156    
157      /**
158       * Retrieves the trace string that will be included with the bind request.
159       *
160       * @return  The trace string that will be included with the bind request, or
161       *          {@code null} if there is to be no trace string.
162       */
163      public String getTraceString()
164      {
165        return traceString;
166      }
167    
168    
169    
170      /**
171       * Sends this bind request to the target server over the provided connection
172       * and returns the corresponding response.
173       *
174       * @param  connection  The connection to use to send this bind request to the
175       *                     server and read the associated response.
176       * @param  depth       The current referral depth for this request.  It should
177       *                     always be one for the initial request, and should only
178       *                     be incremented when following referrals.
179       *
180       * @return  The bind response read from the server.
181       *
182       * @throws  LDAPException  If a problem occurs while sending the request or
183       *                         reading the response.
184       */
185      @Override()
186      protected BindResult process(final LDAPConnection connection, final int depth)
187                throws LDAPException
188      {
189        ASN1OctetString credentials = null;
190        if ((traceString == null) || (traceString.length() == 0))
191        {
192          credentials = new ASN1OctetString(traceString);
193        }
194    
195        return sendBindRequest(connection, null, credentials, getControls(),
196                               getResponseTimeoutMillis(connection));
197      }
198    
199    
200    
201      /**
202       * {@inheritDoc}
203       */
204      @Override()
205      public ANONYMOUSBindRequest getRebindRequest(final String host,
206                                                   final int port)
207      {
208        return new ANONYMOUSBindRequest(traceString, getControls());
209      }
210    
211    
212    
213      /**
214       * {@inheritDoc}
215       */
216      @Override()
217      public ANONYMOUSBindRequest duplicate()
218      {
219        return duplicate(getControls());
220      }
221    
222    
223    
224      /**
225       * {@inheritDoc}
226       */
227      @Override()
228      public ANONYMOUSBindRequest duplicate(final Control[] controls)
229      {
230        final ANONYMOUSBindRequest bindRequest =
231             new ANONYMOUSBindRequest(traceString, controls);
232        bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
233        return bindRequest;
234      }
235    
236    
237    
238      /**
239       * {@inheritDoc}
240       */
241      @Override()
242      public void toString(final StringBuilder buffer)
243      {
244        buffer.append("ANONYMOUSBindRequest(");
245        if (traceString != null)
246        {
247          buffer.append(", trace='");
248          buffer.append(traceString);
249          buffer.append('\'');
250        }
251    
252        final Control[] controls = getControls();
253        if (controls.length > 0)
254        {
255          buffer.append(", controls={");
256          for (int i=0; i < controls.length; i++)
257          {
258            if (i > 0)
259            {
260              buffer.append(", ");
261            }
262    
263            buffer.append(controls[i]);
264          }
265          buffer.append('}');
266        }
267    
268        buffer.append(')');
269      }
270    
271    
272    
273      /**
274       * {@inheritDoc}
275       */
276      @Override()
277      public void toCode(final List<String> lineList, final String requestID,
278                         final int indentSpaces, final boolean includeProcessing)
279      {
280        // Create the request variable.
281        final ArrayList<ToCodeArgHelper> constructorArgs =
282             new ArrayList<ToCodeArgHelper>(2);
283        constructorArgs.add(ToCodeArgHelper.createString(traceString,
284             "Trace String"));
285    
286        final Control[] controls = getControls();
287        if (controls.length > 0)
288        {
289          constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
290               "Bind Controls"));
291        }
292    
293        ToCodeHelper.generateMethodCall(lineList, indentSpaces,
294             "ANONYMOUSBindRequest", requestID + "Request",
295             "new ANONYMOUSBindRequest", constructorArgs);
296    
297    
298        // Add lines for processing the request and obtaining the result.
299        if (includeProcessing)
300        {
301          // Generate a string with the appropriate indent.
302          final StringBuilder buffer = new StringBuilder();
303          for (int i=0; i < indentSpaces; i++)
304          {
305            buffer.append(' ');
306          }
307          final String indent = buffer.toString();
308    
309          lineList.add("");
310          lineList.add(indent + "try");
311          lineList.add(indent + '{');
312          lineList.add(indent + "  BindResult " + requestID +
313               "Result = connection.bind(" + requestID + "Request);");
314          lineList.add(indent + "  // The bind was processed successfully.");
315          lineList.add(indent + '}');
316          lineList.add(indent + "catch (LDAPException e)");
317          lineList.add(indent + '{');
318          lineList.add(indent + "  // The bind failed.  Maybe the following will " +
319               "help explain why.");
320          lineList.add(indent + "  // Note that the connection is now likely in " +
321               "an unauthenticated state.");
322          lineList.add(indent + "  ResultCode resultCode = e.getResultCode();");
323          lineList.add(indent + "  String message = e.getMessage();");
324          lineList.add(indent + "  String matchedDN = e.getMatchedDN();");
325          lineList.add(indent + "  String[] referralURLs = e.getReferralURLs();");
326          lineList.add(indent + "  Control[] responseControls = " +
327               "e.getResponseControls();");
328          lineList.add(indent + '}');
329        }
330      }
331    }