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 Alcatel-Lucent 8661
055 *   server products.  These classes provide support for proprietary
056 *   functionality or for external specifications that are not considered stable
057 *   or mature enough to be guaranteed to work in an interoperable way with
058 *   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  /**
115   * Creates a new validate TOTP password extended request with the provided
116   * information.
117   *
118   * @param  userDN        The DN of the user for whom to validate the TOTP
119   *                       password.
120   * @param  totpPassword  The TOTP password to validate.
121   * @param  controls      The set of controls to include in the request.
122   */
123  public ValidateTOTPPasswordExtendedRequest(final String userDN,
124                                             final String totpPassword,
125                                             final Control... controls)
126  {
127    super(VALIDATE_TOTP_PASSWORD_REQUEST_OID,
128         encodeValue(userDN, totpPassword), controls);
129
130    Validator.ensureNotNull(userDN);
131    Validator.ensureNotNull(totpPassword);
132
133    this.userDN       = userDN;
134    this.totpPassword = totpPassword;
135  }
136
137
138
139  /**
140   * Creates a new validate TOTP password extended request from the provided
141   * generic extended request.
142   *
143   * @param  extendedRequest  The generic extended request to parse as a
144   *                          validate TOTP extended request.
145   *
146   * @throws  LDAPException  If a problem is encountered while attempting to
147   *                         parse the provided extended request.
148   */
149  public ValidateTOTPPasswordExtendedRequest(
150              final ExtendedRequest extendedRequest)
151         throws LDAPException
152  {
153    super(extendedRequest);
154
155    final ASN1OctetString value = extendedRequest.getValue();
156    if (value == null)
157    {
158      throw new LDAPException(ResultCode.DECODING_ERROR,
159           ERR_VALIDATE_TOTP_REQUEST_MISSING_VALUE.get());
160    }
161
162    try
163    {
164      final ASN1Element[] elements =
165           ASN1Sequence.decodeAsSequence(value.getValue()).elements();
166      userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
167      totpPassword =
168           ASN1OctetString.decodeAsOctetString(elements[1]).stringValue();
169    }
170    catch (final Exception e)
171    {
172      Debug.debugException(e);
173      throw new LDAPException(ResultCode.DECODING_ERROR,
174           ERR_VALIDATE_TOTP_REQUEST_MALFORMED_VALUE.get(
175                StaticUtils.getExceptionMessage(e)),
176           e);
177    }
178  }
179
180
181
182  /**
183   * Encodes the provided information into a value suitable for use as the value
184   * for this extended request.
185   *
186   * @param  userDN        The DN of the user for whom to validate the TOTP
187   *                       password.
188   * @param  totpPassword  The TOTP password to validate.
189   *
190   * @return  The ASN.1 octet string containing the encoded value.
191   */
192  private static ASN1OctetString encodeValue(final String userDN,
193                                             final String totpPassword)
194  {
195    return new ASN1OctetString(new ASN1Sequence(
196         new ASN1OctetString(TYPE_USER_DN, userDN),
197         new ASN1OctetString(TYPE_TOTP_PASSWORD, totpPassword)).encode());
198  }
199
200
201
202  /**
203   * Retrieves the DN of the user for whom to validate the TOTP password.
204   *
205   * @return  The DN of the user for whom to validate the TOTP password.
206   */
207  public String getUserDN()
208  {
209    return userDN;
210  }
211
212
213
214  /**
215   * Retrieves the TOTP password to validate.
216   *
217   * @return  The TOTP password to validate.
218   */
219  public String getTOTPPassword()
220  {
221    return totpPassword;
222  }
223
224
225
226  /**
227   * {@inheritDoc}
228   */
229  @Override()
230  public ValidateTOTPPasswordExtendedRequest duplicate()
231  {
232    return duplicate(getControls());
233  }
234
235
236
237  /**
238   * {@inheritDoc}
239   */
240  @Override()
241  public ValidateTOTPPasswordExtendedRequest duplicate(
242              final Control[] controls)
243  {
244    final ValidateTOTPPasswordExtendedRequest r =
245         new ValidateTOTPPasswordExtendedRequest(userDN, totpPassword,
246              controls);
247    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
248    return r;
249  }
250
251
252
253  /**
254   * {@inheritDoc}
255   */
256  @Override()
257  public String getExtendedRequestName()
258  {
259    return INFO_EXTENDED_REQUEST_NAME_VALIDATE_TOTP.get();
260  }
261
262
263
264  /**
265   * {@inheritDoc}
266   */
267  @Override()
268  public void toString(final StringBuilder buffer)
269  {
270    buffer.append("ValidateTOTPPasswordExtendedRequest(userDN='");
271    buffer.append(userDN);
272    buffer.append('\'');
273
274    final Control[] controls = getControls();
275    if (controls.length > 0)
276    {
277      buffer.append(", controls={");
278      for (int i=0; i < controls.length; i++)
279      {
280        if (i > 0)
281        {
282          buffer.append(", ");
283        }
284
285        buffer.append(controls[i]);
286      }
287      buffer.append('}');
288    }
289
290    buffer.append(')');
291  }
292}