001    /*
002     * Copyright 2011-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2011-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    import com.unboundid.util.Validator;
033    
034    
035    
036    /**
037     * This class provides a mechanism for performing SASL authentication in a
038     * generic manner.  The caller is responsible for properly encoding the
039     * credentials (if any) and interpreting the result.  Further, if the requested
040     * SASL mechanism is one that requires multiple stages, then the caller is
041     * responsible for all processing in each stage.
042     */
043    @NotMutable()
044    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
045    public final class GenericSASLBindRequest
046           extends SASLBindRequest
047    {
048      /**
049       * The serial version UID for this serializable class.
050       */
051      private static final long serialVersionUID = 7740968332104559230L;
052    
053    
054    
055      // The SASL credentials that should be used for the bind request.
056      private final ASN1OctetString credentials;
057    
058      // The bind DN to use for the bind request.
059      private final String bindDN;
060    
061      // The name of the SASL mechanism that should be used for the bind request.
062      private final String mechanism;
063    
064    
065    
066      /**
067       * Creates a new generic SASL bind request with the provided information.
068       *
069       * @param  bindDN       The bind DN that should be used for the request.  It
070       *                      may be {@code null} if the target identity should be
071       *                      derived from the credentials or some other source.
072       * @param  mechanism    The name of the mechanism that should be used for the
073       *                      SASL bind.  It must not be {@code null}.
074       * @param  credentials  The credentials that should be used for the SASL bind.
075       *                      It may be {@code null} if no credentials should be
076       *                      used.
077       * @param  controls     The set of controls to include in the SASL bind
078       *                      request.  It may be {@code null} or empty if no
079       *                      request controls are needed.
080       */
081      public GenericSASLBindRequest(final String bindDN, final String mechanism,
082                                    final ASN1OctetString credentials,
083                                    final Control... controls)
084      {
085        super(controls);
086    
087        Validator.ensureNotNull(mechanism);
088    
089        this.bindDN      = bindDN;
090        this.mechanism   = mechanism;
091        this.credentials = credentials;
092      }
093    
094    
095    
096      /**
097       * Retrieves the bind DN for this SASL bind request, if any.
098       *
099       * @return  The bind DN for this SASL bind request, or {@code null} if the
100       *          target identity should be determined from the credentials or some
101       *          other mechanism.
102       */
103      public String getBindDN()
104      {
105        return bindDN;
106      }
107    
108    
109    
110      /**
111       * {@inheritDoc}
112       */
113      @Override()
114      public String getSASLMechanismName()
115      {
116        return mechanism;
117      }
118    
119    
120    
121      /**
122       * Retrieves the credentials for the SASL bind request, if any.
123       *
124       * @return  The credentials for the SASL bind request, or {@code null} if
125       *          there are none.
126       */
127      public ASN1OctetString getCredentials()
128      {
129        return credentials;
130      }
131    
132    
133    
134      /**
135       * {@inheritDoc}
136       */
137      @Override()
138      protected BindResult process(final LDAPConnection connection, final int depth)
139                throws LDAPException
140      {
141        return sendBindRequest(connection, bindDN, credentials, getControls(),
142             getResponseTimeoutMillis(connection));
143      }
144    
145    
146    
147      /**
148       * {@inheritDoc}
149       */
150      @Override()
151      public GenericSASLBindRequest duplicate()
152      {
153        return duplicate(getControls());
154      }
155    
156    
157    
158      /**
159       * {@inheritDoc}
160       */
161      @Override()
162      public GenericSASLBindRequest duplicate(final Control[] controls)
163      {
164        return new GenericSASLBindRequest(bindDN, mechanism, credentials,
165             controls);
166      }
167    
168    
169    
170      /**
171       * {@inheritDoc}
172       */
173      @Override()
174      public void toString(final StringBuilder buffer)
175      {
176        buffer.append("GenericSASLBindRequest(mechanism='");
177        buffer.append(mechanism);
178        buffer.append('\'');
179    
180        if (bindDN != null)
181        {
182          buffer.append(", bindDN='");
183          buffer.append(bindDN);
184          buffer.append('\'');
185        }
186    
187        if (credentials != null)
188        {
189          buffer.append(", credentials=byte[");
190          buffer.append(credentials.getValueLength());
191          buffer.append(']');
192        }
193    
194        final Control[] controls = getControls();
195        if (controls.length > 0)
196        {
197          buffer.append(", controls={");
198          for (int i=0; i < controls.length; i++)
199          {
200            if (i > 0)
201            {
202              buffer.append(", ");
203            }
204    
205            buffer.append(controls[i]);
206          }
207          buffer.append('}');
208        }
209    
210        buffer.append(')');
211      }
212    
213    
214    
215      /**
216       * {@inheritDoc}
217       */
218      @Override()
219      public void toCode(final List<String> lineList, final String requestID,
220                         final int indentSpaces, final boolean includeProcessing)
221      {
222        // Create the request variable.
223        final ArrayList<ToCodeArgHelper> constructorArgs =
224             new ArrayList<ToCodeArgHelper>(4);
225        constructorArgs.add(ToCodeArgHelper.createString(bindDN, "Bind DN"));
226        constructorArgs.add(ToCodeArgHelper.createString(mechanism,
227             "SASL Mechanism Name"));
228        constructorArgs.add(ToCodeArgHelper.createByteArray(
229             "---redacted-SASL-credentials".getBytes(), true,
230             "SASL Credentials"));
231    
232        final Control[] controls = getControls();
233        if (controls.length > 0)
234        {
235          constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
236               "Bind Controls"));
237        }
238    
239        ToCodeHelper.generateMethodCall(lineList, indentSpaces,
240             "GenericSASLBindRequest", requestID + "Request",
241             "new GenericSASLBindRequest", constructorArgs);
242    
243    
244        // Add lines for processing the request and obtaining the result.
245        if (includeProcessing)
246        {
247          // Generate a string with the appropriate indent.
248          final StringBuilder buffer = new StringBuilder();
249          for (int i=0; i < indentSpaces; i++)
250          {
251            buffer.append(' ');
252          }
253          final String indent = buffer.toString();
254    
255          lineList.add("");
256          lineList.add(indent + '{');
257          lineList.add(indent + "  BindResult " + requestID +
258               "Result = connection.bind(" + requestID + "Request);");
259          lineList.add(indent + "  // The bind was processed successfully.");
260          lineList.add(indent + '}');
261          lineList.add(indent + "catch (SASLBindInProgressException e)");
262          lineList.add(indent + '{');
263          lineList.add(indent + "  // The SASL bind requires multiple stages.  " +
264               "Continue it here.");
265          lineList.add(indent + "  // Do not attempt to use the connection for " +
266               "any other purpose until bind processing has completed.");
267          lineList.add(indent + '}');
268          lineList.add(indent + "catch (LDAPException e)");
269          lineList.add(indent + '{');
270          lineList.add(indent + "  // The bind failed.  Maybe the following will " +
271               "help explain why.");
272          lineList.add(indent + "  // Note that the connection is now likely in " +
273               "an unauthenticated state.");
274          lineList.add(indent + "  ResultCode resultCode = e.getResultCode();");
275          lineList.add(indent + "  String message = e.getMessage();");
276          lineList.add(indent + "  String matchedDN = e.getMatchedDN();");
277          lineList.add(indent + "  String[] referralURLs = e.getReferralURLs();");
278          lineList.add(indent + "  Control[] responseControls = " +
279               "e.getResponseControls();");
280          lineList.add(indent + '}');
281        }
282      }
283    }