001/*
002 * Copyright 2011-2022 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2011-2022 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2011-2022 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.ldap.sdk;
037
038
039
040import java.nio.charset.StandardCharsets;
041import java.util.ArrayList;
042import java.util.List;
043
044import com.unboundid.asn1.ASN1OctetString;
045import com.unboundid.util.NotMutable;
046import com.unboundid.util.NotNull;
047import com.unboundid.util.Nullable;
048import com.unboundid.util.ThreadSafety;
049import com.unboundid.util.ThreadSafetyLevel;
050import com.unboundid.util.Validator;
051
052
053
054/**
055 * This class provides a mechanism for performing SASL authentication in a
056 * generic manner.  The caller is responsible for properly encoding the
057 * credentials (if any) and interpreting the result.  Further, if the requested
058 * SASL mechanism is one that requires multiple stages, then the caller is
059 * responsible for all processing in each stage.
060 */
061@NotMutable()
062@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
063public final class GenericSASLBindRequest
064       extends SASLBindRequest
065{
066  /**
067   * The serial version UID for this serializable class.
068   */
069  private static final long serialVersionUID = 7740968332104559230L;
070
071
072
073  // The SASL credentials that should be used for the bind request.
074  @Nullable private final ASN1OctetString credentials;
075
076  // The bind DN to use for the bind request.
077  @Nullable private final String bindDN;
078
079  // The name of the SASL mechanism that should be used for the bind request.
080  @NotNull private final String mechanism;
081
082
083
084  /**
085   * Creates a new generic SASL bind request with the provided information.
086   *
087   * @param  bindDN       The bind DN that should be used for the request.  It
088   *                      may be {@code null} if the target identity should be
089   *                      derived from the credentials or some other source.
090   * @param  mechanism    The name of the mechanism that should be used for the
091   *                      SASL bind.  It must not be {@code null}.
092   * @param  credentials  The credentials that should be used for the SASL bind.
093   *                      It may be {@code null} if no credentials should be
094   *                      used.
095   * @param  controls     The set of controls to include in the SASL bind
096   *                      request.  It may be {@code null} or empty if no
097   *                      request controls are needed.
098   */
099  public GenericSASLBindRequest(@Nullable final String bindDN,
100                                @NotNull final String mechanism,
101                                @Nullable final ASN1OctetString credentials,
102                                @Nullable final Control... controls)
103  {
104    super(controls);
105
106    Validator.ensureNotNull(mechanism);
107
108    this.bindDN      = bindDN;
109    this.mechanism   = mechanism;
110    this.credentials = credentials;
111  }
112
113
114
115  /**
116   * Retrieves the bind DN for this SASL bind request, if any.
117   *
118   * @return  The bind DN for this SASL bind request, or {@code null} if the
119   *          target identity should be determined from the credentials or some
120   *          other mechanism.
121   */
122  @Nullable()
123  public String getBindDN()
124  {
125    return bindDN;
126  }
127
128
129
130  /**
131   * {@inheritDoc}
132   */
133  @Override()
134  @NotNull()
135  public String getSASLMechanismName()
136  {
137    return mechanism;
138  }
139
140
141
142  /**
143   * Retrieves the credentials for the SASL bind request, if any.
144   *
145   * @return  The credentials for the SASL bind request, or {@code null} if
146   *          there are none.
147   */
148  @Nullable()
149  public ASN1OctetString getCredentials()
150  {
151    return credentials;
152  }
153
154
155
156  /**
157   * {@inheritDoc}
158   */
159  @Override()
160  @NotNull()
161  protected BindResult process(@NotNull final LDAPConnection connection,
162                               final int depth)
163            throws LDAPException
164  {
165    return sendBindRequest(connection, bindDN, credentials, getControls(),
166         getResponseTimeoutMillis(connection));
167  }
168
169
170
171  /**
172   * {@inheritDoc}
173   */
174  @Override()
175  @NotNull()
176  public GenericSASLBindRequest duplicate()
177  {
178    return duplicate(getControls());
179  }
180
181
182
183  /**
184   * {@inheritDoc}
185   */
186  @Override()
187  @NotNull()
188  public GenericSASLBindRequest duplicate(@Nullable final Control[] controls)
189  {
190    return new GenericSASLBindRequest(bindDN, mechanism, credentials,
191         controls);
192  }
193
194
195
196  /**
197   * {@inheritDoc}
198   */
199  @Override()
200  public void toString(@NotNull final StringBuilder buffer)
201  {
202    buffer.append("GenericSASLBindRequest(mechanism='");
203    buffer.append(mechanism);
204    buffer.append('\'');
205
206    if (bindDN != null)
207    {
208      buffer.append(", bindDN='");
209      buffer.append(bindDN);
210      buffer.append('\'');
211    }
212
213    if (credentials != null)
214    {
215      buffer.append(", credentials=byte[");
216      buffer.append(credentials.getValueLength());
217      buffer.append(']');
218    }
219
220    final Control[] controls = getControls();
221    if (controls.length > 0)
222    {
223      buffer.append(", controls={");
224      for (int i=0; i < controls.length; i++)
225      {
226        if (i > 0)
227        {
228          buffer.append(", ");
229        }
230
231        buffer.append(controls[i]);
232      }
233      buffer.append('}');
234    }
235
236    buffer.append(')');
237  }
238
239
240
241  /**
242   * {@inheritDoc}
243   */
244  @Override()
245  public void toCode(@NotNull final List<String> lineList,
246                     @NotNull final String requestID,
247                     final int indentSpaces, final boolean includeProcessing)
248  {
249    // Create the request variable.
250    final ArrayList<ToCodeArgHelper> constructorArgs = new ArrayList<>(4);
251    constructorArgs.add(ToCodeArgHelper.createString(bindDN, "Bind DN"));
252    constructorArgs.add(ToCodeArgHelper.createString(mechanism,
253         "SASL Mechanism Name"));
254    constructorArgs.add(ToCodeArgHelper.createByteArray(
255         "---redacted-SASL-credentials".getBytes(StandardCharsets.UTF_8), true,
256         "SASL Credentials"));
257
258    final Control[] controls = getControls();
259    if (controls.length > 0)
260    {
261      constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
262           "Bind Controls"));
263    }
264
265    ToCodeHelper.generateMethodCall(lineList, indentSpaces,
266         "GenericSASLBindRequest", requestID + "Request",
267         "new GenericSASLBindRequest", constructorArgs);
268
269
270    // Add lines for processing the request and obtaining the result.
271    if (includeProcessing)
272    {
273      // Generate a string with the appropriate indent.
274      final StringBuilder buffer = new StringBuilder();
275      for (int i=0; i < indentSpaces; i++)
276      {
277        buffer.append(' ');
278      }
279      final String indent = buffer.toString();
280
281      lineList.add("");
282      lineList.add(indent + '{');
283      lineList.add(indent + "  BindResult " + requestID +
284           "Result = connection.bind(" + requestID + "Request);");
285      lineList.add(indent + "  // The bind was processed successfully.");
286      lineList.add(indent + '}');
287      lineList.add(indent + "catch (SASLBindInProgressException e)");
288      lineList.add(indent + '{');
289      lineList.add(indent + "  // The SASL bind requires multiple stages.  " +
290           "Continue it here.");
291      lineList.add(indent + "  // Do not attempt to use the connection for " +
292           "any other purpose until bind processing has completed.");
293      lineList.add(indent + '}');
294      lineList.add(indent + "catch (LDAPException e)");
295      lineList.add(indent + '{');
296      lineList.add(indent + "  // The bind failed.  Maybe the following will " +
297           "help explain why.");
298      lineList.add(indent + "  // Note that the connection is now likely in " +
299           "an unauthenticated state.");
300      lineList.add(indent + "  ResultCode resultCode = e.getResultCode();");
301      lineList.add(indent + "  String message = e.getMessage();");
302      lineList.add(indent + "  String matchedDN = e.getMatchedDN();");
303      lineList.add(indent + "  String[] referralURLs = e.getReferralURLs();");
304      lineList.add(indent + "  Control[] responseControls = " +
305           "e.getResponseControls();");
306      lineList.add(indent + '}');
307    }
308  }
309}