001/*
002 * Copyright 2012-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2018 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.unboundidds.extensions;
022
023
024
025import com.unboundid.asn1.ASN1Element;
026import com.unboundid.asn1.ASN1OctetString;
027import com.unboundid.asn1.ASN1Sequence;
028import com.unboundid.ldap.sdk.Control;
029import com.unboundid.ldap.sdk.ExtendedRequest;
030import com.unboundid.ldap.sdk.LDAPException;
031import com.unboundid.ldap.sdk.ResultCode;
032import com.unboundid.util.Debug;
033import com.unboundid.util.NotMutable;
034import com.unboundid.util.StaticUtils;
035import com.unboundid.util.ThreadSafety;
036import com.unboundid.util.ThreadSafetyLevel;
037import com.unboundid.util.Validator;
038
039import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
040
041
042
043/**
044 * This class provides an implementation of an extended request which may be
045 * used to validate a TOTP password for a user.  Note that this should not be
046 * used as an alternative to authentication because it does not perform password
047 * policy processing.  Rather, this extended operation should be used only to
048 * obtain additional assurance about the identity of a user that has already
049 * been authenticated through some other means.
050 * <BR>
051 * <BLOCKQUOTE>
052 *   <B>NOTE:</B>  This class, and other classes within the
053 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
054 *   supported for use against Ping Identity, UnboundID, and
055 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
056 *   for proprietary functionality or for external specifications that are not
057 *   considered stable or mature enough to be guaranteed to work in an
058 *   interoperable way with other types of LDAP servers.
059 * </BLOCKQUOTE>
060 * <BR>
061 * The extended request has an OID of 1.3.6.1.4.1.30221.2.6.15 and a value with
062 * the following encoding:
063 * <PRE>
064 *   ValidateTOTPPasswordRequest ::= SEQUENCE {
065 *        userDN           [0] LDAPDN,
066 *        totpPassword     [1] OCTET STRING,
067 *        ... }
068 * </PRE>
069 */
070@NotMutable()
071@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
072public final class ValidateTOTPPasswordExtendedRequest
073       extends ExtendedRequest
074{
075  /**
076   * The OID (1.3.6.1.4.1.30221.2.6.15) for the validate TOTP password extended
077   * request.
078   */
079  public static final String VALIDATE_TOTP_PASSWORD_REQUEST_OID =
080       "1.3.6.1.4.1.30221.2.6.15";
081
082
083
084  /**
085   * The BER type for the user DN value element.
086   */
087  private static final byte TYPE_USER_DN = (byte) 0x80;
088
089
090
091  /**
092   * The BER type for the TOTP password value element.
093   */
094  private static final byte TYPE_TOTP_PASSWORD = (byte) 0x81;
095
096
097
098  /**
099   * The serial version UID for this serializable class.
100   */
101  private static final long serialVersionUID = -4610279612454559569L;
102
103
104
105  // The DN of the user for whom to validate the TOTP password.
106  private final String userDN;
107
108  // The TOTP password to validate.
109  private final String totpPassword;
110
111
112
113  /**
114   * Creates a new validate TOTP password extended request with the provided
115   * information.
116   *
117   * @param  userDN        The DN of the user for whom to validate the TOTP
118   *                       password.
119   * @param  totpPassword  The TOTP password to validate.
120   * @param  controls      The set of controls to include in the request.
121   */
122  public ValidateTOTPPasswordExtendedRequest(final String userDN,
123                                             final String totpPassword,
124                                             final Control... controls)
125  {
126    super(VALIDATE_TOTP_PASSWORD_REQUEST_OID,
127         encodeValue(userDN, totpPassword), controls);
128
129    Validator.ensureNotNull(userDN);
130    Validator.ensureNotNull(totpPassword);
131
132    this.userDN       = userDN;
133    this.totpPassword = totpPassword;
134  }
135
136
137
138  /**
139   * Creates a new validate TOTP password extended request from the provided
140   * generic extended request.
141   *
142   * @param  extendedRequest  The generic extended request to parse as a
143   *                          validate TOTP extended request.
144   *
145   * @throws  LDAPException  If a problem is encountered while attempting to
146   *                         parse the provided extended request.
147   */
148  public ValidateTOTPPasswordExtendedRequest(
149              final ExtendedRequest extendedRequest)
150         throws LDAPException
151  {
152    super(extendedRequest);
153
154    final ASN1OctetString value = extendedRequest.getValue();
155    if (value == null)
156    {
157      throw new LDAPException(ResultCode.DECODING_ERROR,
158           ERR_VALIDATE_TOTP_REQUEST_MISSING_VALUE.get());
159    }
160
161    try
162    {
163      final ASN1Element[] elements =
164           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
165      userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
166      totpPassword =
167           ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
168    }
169    catch (final Exception e)
170    {
171      Debug.debugException(e);
172      throw new LDAPException(ResultCode.DECODING_ERROR,
173           ERR_VALIDATE_TOTP_REQUEST_MALFORMED_VALUE.get(
174                StaticUtils.getExceptionMessage(e)),
175           e);
176    }
177  }
178
179
180
181  /**
182   * Encodes the provided information into a value suitable for use as the value
183   * for this extended request.
184   *
185   * @param  userDN        The DN of the user for whom to validate the TOTP
186   *                       password.
187   * @param  totpPassword  The TOTP password to validate.
188   *
189   * @return  The ASN.1 octet string containing the encoded value.
190   */
191  private static ASN1OctetString encodeValue(final String userDN,
192                                             final String totpPassword)
193  {
194    return new ASN1OctetString(new ASN1Sequence(
195         new ASN1OctetString(TYPE_USER_DN, userDN),
196         new ASN1OctetString(TYPE_TOTP_PASSWORD, totpPassword)).encode());
197  }
198
199
200
201  /**
202   * Retrieves the DN of the user for whom to validate the TOTP password.
203   *
204   * @return  The DN of the user for whom to validate the TOTP password.
205   */
206  public String getUserDN()
207  {
208    return userDN;
209  }
210
211
212
213  /**
214   * Retrieves the TOTP password to validate.
215   *
216   * @return  The TOTP password to validate.
217   */
218  public String getTOTPPassword()
219  {
220    return totpPassword;
221  }
222
223
224
225  /**
226   * {@inheritDoc}
227   */
228  @Override()
229  public ValidateTOTPPasswordExtendedRequest duplicate()
230  {
231    return duplicate(getControls());
232  }
233
234
235
236  /**
237   * {@inheritDoc}
238   */
239  @Override()
240  public ValidateTOTPPasswordExtendedRequest duplicate(
241              final Control[] controls)
242  {
243    final ValidateTOTPPasswordExtendedRequest r =
244         new ValidateTOTPPasswordExtendedRequest(userDN, totpPassword,
245              controls);
246    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
247    return r;
248  }
249
250
251
252  /**
253   * {@inheritDoc}
254   */
255  @Override()
256  public String getExtendedRequestName()
257  {
258    return INFO_EXTENDED_REQUEST_NAME_VALIDATE_TOTP.get();
259  }
260
261
262
263  /**
264   * {@inheritDoc}
265   */
266  @Override()
267  public void toString(final StringBuilder buffer)
268  {
269    buffer.append("ValidateTOTPPasswordExtendedRequest(userDN='");
270    buffer.append(userDN);
271    buffer.append('\'');
272
273    final Control[] controls = getControls();
274    if (controls.length > 0)
275    {
276      buffer.append(", controls={");
277      for (int i=0; i < controls.length; i++)
278      {
279        if (i > 0)
280        {
281          buffer.append(", ");
282        }
283
284        buffer.append(controls[i]);
285      }
286      buffer.append('}');
287    }
288
289    buffer.append(')');
290  }
291}