001/*
002 * Copyright 2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2019 Ping Identity Corporation
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 */
021package com.unboundid.ldap.sdk;
022
023
024
025import java.util.ArrayList;
026import java.util.List;
027
028import com.unboundid.asn1.ASN1OctetString;
029import com.unboundid.util.ThreadSafety;
030import com.unboundid.util.ThreadSafetyLevel;
031
032
033
034/**
035 * This class provides an implementation of the SCRAM-SHA-256 SASL mechanism as
036 * described in <A HREF="http://www.ietf.org/rfc/rfc7677.txt">RFC 7677</A>.
037 */
038@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
039public final class SCRAMSHA256BindRequest
040       extends SCRAMBindRequest
041{
042  /**
043   * The serial version UID for this serializable class.
044   */
045  private static final long serialVersionUID = -4396660110665214258L;
046
047
048
049  /**
050   * Creates a new SCRAM-SHA-256 bind request with the provided information.
051   *
052   * @param username The username for this bind request.  It must not be {@code
053   *                 null} or empty.
054   * @param password The password for this bind request.  It must not be {@code
055   *                 null} or empty.
056   * @param controls The set of controls to include in the bind request.  It may
057   *                 be {@code null} or empty if no controls are needed.
058   */
059  public SCRAMSHA256BindRequest(final String username, final String password,
060                                final Control... controls)
061  {
062    super(username, new ASN1OctetString(password), controls);
063  }
064
065
066
067  /**
068   * Creates a new SCRAM-SHA-256 bind request with the provided information.
069   *
070   * @param username The username for this bind request.  It must not be {@code
071   *                 null} or empty.
072   * @param password The password for this bind request.  It must not be {@code
073   *                 null} or empty.
074   * @param controls The set of controls to include in the bind request.  It may
075   *                 be {@code null} or empty if no controls are needed.
076   */
077  public SCRAMSHA256BindRequest(final String username, final byte[] password,
078                                final Control... controls)
079  {
080    super(username, new ASN1OctetString(password), controls);
081  }
082
083
084
085  /**
086   * {@inheritDoc}
087   */
088  @Override()
089  public String getSASLMechanismName()
090  {
091    return "SCRAM-SHA-256";
092  }
093
094
095
096  /**
097   * {@inheritDoc}
098   */
099  @Override()
100  protected String getDigestAlgorithmName()
101  {
102    return "SHA-256";
103  }
104
105
106
107  /**
108   * {@inheritDoc}
109   */
110  @Override()
111  protected String getMACAlgorithmName()
112  {
113    return "HmacSHA256";
114  }
115
116
117
118  /**
119   * {@inheritDoc}
120   */
121  @Override()
122  public SCRAMSHA256BindRequest getRebindRequest(final String host,
123                                                 final int port)
124  {
125    return duplicate();
126  }
127
128
129
130  /**
131   * {@inheritDoc}
132   */
133  @Override()
134  public SCRAMSHA256BindRequest duplicate()
135  {
136    return duplicate(getControls());
137  }
138
139
140
141  /**
142   * {@inheritDoc}
143   */
144  @Override()
145  public SCRAMSHA256BindRequest duplicate(final Control[] controls)
146  {
147    return new SCRAMSHA256BindRequest(getUsername(), getPasswordBytes(),
148         controls);
149  }
150
151
152
153  /**
154   * {@inheritDoc}
155   */
156  @Override()
157  public void toString(final StringBuilder buffer)
158  {
159    buffer.append("SCRAMSHA256BindRequest(username='");
160    buffer.append(getUsername());
161    buffer.append('\'');
162
163    final Control[] controls = getControls();
164    if (controls.length > 0)
165    {
166      buffer.append(", controls={");
167      for (int i=0; i < controls.length; i++)
168      {
169        if (i > 0)
170        {
171          buffer.append(", ");
172        }
173
174        buffer.append(controls[i]);
175      }
176      buffer.append('}');
177    }
178
179    buffer.append(')');
180  }
181
182
183
184  /**
185   * {@inheritDoc}
186   */
187  @Override()
188  public void toCode(final List<String> lineList, final String requestID,
189                     final int indentSpaces, final boolean includeProcessing)
190  {
191    // Create the request variable.
192    final List<ToCodeArgHelper> constructorArgs = new ArrayList<>(4);
193    constructorArgs.add(ToCodeArgHelper.createString(getUsername(),
194         "Username"));
195    constructorArgs.add(ToCodeArgHelper.createString("---redacted-password---",
196         "Password"));
197
198    final Control[] controls = getControls();
199    if (controls.length > 0)
200    {
201      constructorArgs.add(ToCodeArgHelper.createControlArray(controls,
202           "Bind Controls"));
203    }
204
205    ToCodeHelper.generateMethodCall(lineList, indentSpaces,
206         "SCRAMSHA256BindRequest", requestID + "Request",
207         "new SCRAMSHA256BindRequest", constructorArgs);
208
209
210    // Add lines for processing the request and obtaining the result.
211    if (includeProcessing)
212    {
213      // Generate a string with the appropriate indent.
214      final StringBuilder buffer = new StringBuilder();
215      for (int i=0; i < indentSpaces; i++)
216      {
217        buffer.append(' ');
218      }
219      final String indent = buffer.toString();
220
221      lineList.add("");
222      lineList.add(indent + "try");
223      lineList.add(indent + '{');
224      lineList.add(indent + "  BindResult " + requestID +
225           "Result = connection.bind(" + requestID + "Request);");
226      lineList.add(indent + "  // The bind was processed successfully.");
227      lineList.add(indent + '}');
228      lineList.add(indent + "catch (LDAPException e)");
229      lineList.add(indent + '{');
230      lineList.add(indent + "  // The bind failed.  Maybe the following will " +
231           "help explain why.");
232      lineList.add(indent + "  // Note that the connection is now likely in " +
233           "an unauthenticated state.");
234      lineList.add(indent + "  ResultCode resultCode = e.getResultCode();");
235      lineList.add(indent + "  String message = e.getMessage();");
236      lineList.add(indent + "  String matchedDN = e.getMatchedDN();");
237      lineList.add(indent + "  String[] referralURLs = e.getReferralURLs();");
238      lineList.add(indent + "  Control[] responseControls = " +
239           "e.getResponseControls();");
240      lineList.add(indent + '}');
241    }
242  }
243}