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