001/*
002 * Copyright 2016-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2016-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 java.util.ArrayList;
026
027import com.unboundid.asn1.ASN1Element;
028import com.unboundid.asn1.ASN1OctetString;
029import com.unboundid.asn1.ASN1Sequence;
030import com.unboundid.ldap.sdk.Control;
031import com.unboundid.ldap.sdk.ExtendedRequest;
032import com.unboundid.ldap.sdk.LDAPException;
033import com.unboundid.ldap.sdk.ResultCode;
034import com.unboundid.util.Debug;
035import com.unboundid.util.NotMutable;
036import com.unboundid.util.StaticUtils;
037import com.unboundid.util.ThreadSafety;
038import com.unboundid.util.ThreadSafetyLevel;
039
040import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
041
042
043
044/**
045 * This class provides an implementation of an extended request that may be used
046 * to deregister a YubiKey OTP device with the Directory Server so that it may
047 * no longer used to authenticate using the UNBOUNDID-YUBIKEY-OTP SASL
048 * mechanism.
049 * <BR>
050 * <BLOCKQUOTE>
051 *   <B>NOTE:</B>  This class, and other classes within the
052 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
053 *   supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661
054 *   server products.  These classes provide support for proprietary
055 *   functionality or for external specifications that are not considered stable
056 *   or mature enough to be guaranteed to work in an interoperable way with
057 *   other types of LDAP servers.
058 * </BLOCKQUOTE>
059 * <BR>
060 * This extended request has an OID of 1.3.6.1.4.1.30221.2.6.55, and it must
061 * include a request value with the following encoding:
062 * <BR><BR>
063 * <PRE>
064 *   DeregisterYubiKeyOTPDeviceRequest ::= SEQUENCE {
065 *        authenticationID     [0] OCTET STRING OPTIONAL,
066 *        staticPassword       [1] OCTET STRING OPTIONAL,
067 *        yubiKeyOTP           [2] OCTET STRING OPTIONAL,
068 *        ... }
069 * </PRE>
070 *
071 *
072 * @see  RegisterYubiKeyOTPDeviceExtendedRequest
073 * @see  com.unboundid.ldap.sdk.unboundidds.UnboundIDYubiKeyOTPBindRequest
074 * @see  com.unboundid.ldap.sdk.unboundidds.RegisterYubiKeyOTPDevice
075 */
076@NotMutable()
077@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
078public final class DeregisterYubiKeyOTPDeviceExtendedRequest
079       extends ExtendedRequest
080{
081  /**
082   * The OID (1.3.6.1.4.1.30221.2.6.55) for the deregister YubiKey OTP device
083   * extended request.
084   */
085  public static final String DEREGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID =
086       "1.3.6.1.4.1.30221.2.6.55";
087
088
089
090  /**
091   * The BER type for the authentication ID element of the request value
092   * sequence.
093   */
094  private static final byte TYPE_AUTHENTICATION_ID = (byte) 0x80;
095
096
097
098  /**
099   * The BER type for the static password element of the request value sequence.
100   */
101  private static final byte TYPE_STATIC_PASSWORD = (byte) 0x81;
102
103
104
105  /**
106   * The BER type for the YubiKey OTP element of the request value sequence.
107   */
108  private static final byte TYPE_YUBIKEY_OTP = (byte) 0x82;
109
110
111
112  /**
113   * The serial version UID for this serializable class.
114   */
115  private static final long serialVersionUID = -4029230013825076585L;
116
117
118
119  // The static password for the request.
120  private final ASN1OctetString staticPassword;
121
122  // The authentication ID for the request.
123  private final String authenticationID;
124
125  // The YubiKey OTP for the request.
126  private final String yubiKeyOTP;
127
128
129
130  /**
131   * Creates a new deregister YubiKey OTP device extended request with the
132   * provided information.
133   *
134   * @param  authenticationID  The authentication ID that identifies the user
135   *                           for whom the YubiKey OTP device is to be
136   *                           deregistered.  It may be {@code null} if the
137   *                           device is to be deregistered for the user as whom
138   *                           the underlying connection is authenticated.
139   * @param  yubiKeyOTP        An optional one-time password generated by the
140   *                           YubiKey device to be deregistered.  If this is
141   *                           {@code null}, then all YubiKey OTP devices
142   *                           associated with the target user will be
143   *                           deregistered.  If it is non-{@code null}, then
144   *                           only the YubiKey device used to generate the OTP
145   *                           will be deregistered.
146   * @param  controls          The set of controls to include in the request.
147   *                           It may be {@code null} or empty if there should
148   *                           not be any request controls.
149   */
150  public DeregisterYubiKeyOTPDeviceExtendedRequest(
151              final String authenticationID, final String yubiKeyOTP,
152              final Control... controls)
153  {
154    this(authenticationID, (ASN1OctetString) null, yubiKeyOTP, controls);
155  }
156
157
158
159  /**
160   * Creates a new deregister YubiKey OTP device extended request with the
161   * provided information.
162   *
163   * @param  authenticationID  The authentication ID that identifies the user
164   *                           for whom the YubiKey OTP device is to be
165   *                           deregistered.  It may be {@code null} if the
166   *                           device is to be deregistered for the user as whom
167   *                           the underlying connection is authenticated.
168   * @param  staticPassword    The static password of the user for whom the
169   *                           device is to be deregistered.  It may be
170   *                           {@code null} if the server is configured to not
171   *                           require a static password when deregistering one
172   *                           or more devices.
173   * @param  yubiKeyOTP        An optional one-time password generated by the
174   *                           YubiKey device to be deregistered.  If this is
175   *                           {@code null}, then all YubiKey OTP devices
176   *                           associated with the target user will be
177   *                           deregistered.  If it is non-{@code null}, then
178   *                           only the YubiKey device used to generate the OTP
179   *                           will be deregistered.
180   * @param  controls          The set of controls to include in the request.
181   *                           It may be {@code null} or empty if there should
182   *                           not be any request controls.
183   */
184  public DeregisterYubiKeyOTPDeviceExtendedRequest(
185              final String authenticationID, final String staticPassword,
186              final String yubiKeyOTP, final Control... controls)
187  {
188    this(authenticationID,
189         RegisterYubiKeyOTPDeviceExtendedRequest.encodePassword(staticPassword),
190         yubiKeyOTP, controls);
191  }
192
193
194
195  /**
196   * Creates a new deregister YubiKey OTP device extended request with the
197   * provided information.
198   *
199   * @param  authenticationID  The authentication ID that identifies the user
200   *                           for whom the YubiKey OTP device is to be
201   *                           deregistered.  It may be {@code null} if the
202   *                           device is to be deregistered for the user as whom
203   *                           the underlying connection is authenticated.
204   * @param  staticPassword    The static password of the user for whom the
205   *                           device is to be deregistered.  It may be
206   *                           {@code null} if the server is configured to not
207   *                           require a static password when deregistering one
208   *                           or more devices.
209   * @param  yubiKeyOTP        An optional one-time password generated by the
210   *                           YubiKey device to be deregistered.  If this is
211   *                           {@code null}, then all YubiKey OTP devices
212   *                           associated with the target user will be
213   *                           deregistered.  If it is non-{@code null}, then
214   *                           only the YubiKey device used to generate the OTP
215   *                           will be deregistered.
216   * @param  controls          The set of controls to include in the request.
217   *                           It may be {@code null} or empty if there should
218   *                           not be any request controls.
219   */
220  public DeregisterYubiKeyOTPDeviceExtendedRequest(
221              final String authenticationID, final byte[] staticPassword,
222              final String yubiKeyOTP, final Control... controls)
223  {
224    this(authenticationID,
225         RegisterYubiKeyOTPDeviceExtendedRequest.encodePassword(staticPassword),
226         yubiKeyOTP, controls);
227  }
228
229
230
231  /**
232   * Creates a new deregister YubiKey OTP device extended request with the
233   * provided information.
234   *
235   * @param  authenticationID  The authentication ID that identifies the user
236   *                           for whom the YubiKey OTP device is to be
237   *                           deregistered.  It may be {@code null} if the
238   *                           device is to be deregistered for the user as whom
239   *                           the underlying connection is authenticated.
240   * @param  staticPassword    The static password of the user for whom the
241   *                           device is to be deregistered.  It may be
242   *                           {@code null} if the server is configured to not
243   *                           require a static password when deregistering one
244   *                           or more devices.
245   * @param  yubiKeyOTP        An optional one-time password generated by the
246   *                           YubiKey device to be deregistered.  If this is
247   *                           {@code null}, then all YubiKey OTP devices
248   *                           associated with the target user will be
249   *                           deregistered.  If it is non-{@code null}, then
250   *                           only the YubiKey device used to generate the OTP
251   *                           will be deregistered.
252   * @param  controls          The set of controls to include in the request.
253   *                           It may be {@code null} or empty if there should
254   *                           not be any request controls.
255   */
256  private DeregisterYubiKeyOTPDeviceExtendedRequest(
257               final String authenticationID,
258               final ASN1OctetString staticPassword, final String yubiKeyOTP,
259               final Control... controls)
260  {
261    super(DEREGISTER_YUBIKEY_OTP_DEVICE_REQUEST_OID,
262         encodeValue(authenticationID, staticPassword, yubiKeyOTP), controls);
263
264    this.authenticationID = authenticationID;
265    this.staticPassword   = staticPassword;
266    this.yubiKeyOTP       = yubiKeyOTP;
267  }
268
269
270
271  /**
272   * Creates a new deregister YubiKey OTP device extended request that is
273   * decoded from the provided generic extended request.
274   *
275   * @param  request  The generic extended request to decode as a deregister
276   *                  YubiKey OTP device request.
277   *
278   * @throws  LDAPException  If a problem is encountered while attempting to
279   *                         decode the provided request.
280   */
281  public DeregisterYubiKeyOTPDeviceExtendedRequest(
282              final ExtendedRequest request)
283         throws LDAPException
284  {
285    super(request);
286
287    final ASN1OctetString value = request.getValue();
288    if (value == null)
289    {
290      throw new LDAPException(ResultCode.DECODING_ERROR,
291           ERR_DEREGISTER_YUBIKEY_OTP_REQUEST_NO_VALUE.get());
292    }
293
294    try
295    {
296      String authID = null;
297      ASN1OctetString staticPW = null;
298      String otp = null;
299      for (final ASN1Element e :
300           ASN1Sequence.decodeAsSequence(value.getValue()).elements())
301      {
302        switch (e.getType())
303        {
304          case TYPE_AUTHENTICATION_ID:
305            authID = ASN1OctetString.decodeAsOctetString(e).stringValue();
306            break;
307          case TYPE_STATIC_PASSWORD:
308            staticPW = ASN1OctetString.decodeAsOctetString(e);
309            break;
310          case TYPE_YUBIKEY_OTP:
311            otp = ASN1OctetString.decodeAsOctetString(e).stringValue();
312            break;
313          default:
314            throw new LDAPException(ResultCode.DECODING_ERROR,
315                 ERR_DEREGISTER_YUBIKEY_OTP_REQUEST_UNRECOGNIZED_TYPE.get(
316                      StaticUtils.toHex(e.getType())));
317        }
318      }
319
320      authenticationID = authID;
321      staticPassword   = staticPW;
322      yubiKeyOTP       = otp;
323    }
324    catch (final LDAPException le)
325    {
326      Debug.debugException(le);
327      throw le;
328    }
329    catch (final Exception e)
330    {
331      Debug.debugException(e);
332      throw new LDAPException(ResultCode.DECODING_ERROR,
333           ERR_DEREGISTER_YUBIKEY_OTP_REQUEST_ERROR_DECODING_VALUE.get(
334                StaticUtils.getExceptionMessage(e)),
335           e);
336    }
337  }
338
339
340
341  /**
342   * Encodes the provided information into an ASN.1 octet string suitable for
343   * use as the value of this extended request.
344   *
345   * @param  authenticationID  The authentication ID that identifies the user
346   *                           for whom the YubiKey OTP device is to be
347   *                           deregistered.  It may be {@code null} if the
348   *                           device is to be deregistered for the user as whom
349   *                           the underlying connection is authenticated.
350   * @param  staticPassword    The static password of the user for whom the
351   *                           device is to be deregistered.  It may be
352   *                           {@code null} if the server is configured to not
353   *                           require a static password when deregistering one
354   *                           or more devices.
355   * @param  yubiKeyOTP        An optional one-time password generated by the
356   *                           YubiKey device to be deregistered.  If this is
357   *                           {@code null}, then all YubiKey OTP devices
358   *                           associated with the target user will be
359   *                           deregistered.  If it is non-{@code null}, then
360   *                           only the YubiKey device used to generate the OTP
361   *                           will be deregistered.
362   *
363   * @return  The ASN.1 octet string containing the encoded request value.
364   */
365  private static ASN1OctetString encodeValue(final String authenticationID,
366                                      final ASN1OctetString staticPassword,
367                                      final String yubiKeyOTP)
368  {
369    final ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(3);
370
371    if (authenticationID != null)
372    {
373      elements.add(
374           new ASN1OctetString(TYPE_AUTHENTICATION_ID, authenticationID));
375    }
376
377    if (staticPassword != null)
378    {
379      elements.add(staticPassword);
380    }
381
382    if (yubiKeyOTP != null)
383    {
384      elements.add(new ASN1OctetString(TYPE_YUBIKEY_OTP, yubiKeyOTP));
385    }
386
387    return new ASN1OctetString(new ASN1Sequence(elements).encode());
388  }
389
390
391
392  /**
393   * Retrieves the authentication ID that identifies the user from whom the
394   * YubiKey OTP device is to be deregistered, if provided.
395   *
396   * @return  The authentication ID that identifies the target user, or
397   *          {@code null} if the device is to be deregistered for the user as
398   *          whom the underlying connection is authenticated.
399   */
400  public String getAuthenticationID()
401  {
402    return authenticationID;
403  }
404
405
406
407  /**
408   * Retrieves the string representation of the static password for the target
409   * user, if provided.
410   *
411   * @return  The string representation of the static password for the target
412   *          user, or {@code null} if no static password was provided.
413   */
414  public String getStaticPasswordString()
415  {
416    if (staticPassword == null)
417    {
418      return null;
419    }
420    else
421    {
422      return staticPassword.stringValue();
423    }
424  }
425
426
427
428  /**
429   * Retrieves the bytes that comprise the static password for the target user,
430   * if provided.
431   *
432   * @return  The bytes that comprise the static password for the target user,
433   *          or {@code null} if no static password was provided.
434   */
435  public byte[] getStaticPasswordBytes()
436  {
437    if (staticPassword == null)
438    {
439      return null;
440    }
441    else
442    {
443      return staticPassword.getValue();
444    }
445  }
446
447
448
449  /**
450   * Retrieves a one-time password generated by the YubiKey device to be
451   * deregistered, if provided.
452   *
453   * @return  A one-time password generated by the YubiKey device to be
454   *          deregistered, or {@code null} if all devices associated with the
455   *          target user should be deregistered.
456   */
457  public String getYubiKeyOTP()
458  {
459    return yubiKeyOTP;
460  }
461
462
463
464  /**
465   * {@inheritDoc}
466   */
467  @Override()
468  public DeregisterYubiKeyOTPDeviceExtendedRequest duplicate()
469  {
470    return duplicate(getControls());
471  }
472
473
474
475  /**
476   * {@inheritDoc}
477   */
478  @Override()
479  public DeregisterYubiKeyOTPDeviceExtendedRequest
480              duplicate(final Control[] controls)
481  {
482    final DeregisterYubiKeyOTPDeviceExtendedRequest r =
483         new DeregisterYubiKeyOTPDeviceExtendedRequest(authenticationID,
484              staticPassword, yubiKeyOTP, controls);
485    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
486    return r;
487  }
488
489
490
491  /**
492   * {@inheritDoc}
493   */
494  @Override()
495  public String getExtendedRequestName()
496  {
497    return INFO_DEREGISTER_YUBIKEY_OTP_REQUEST_NAME.get();
498  }
499
500
501
502  /**
503   * {@inheritDoc}
504   */
505  @Override()
506  public void toString(final StringBuilder buffer)
507  {
508    buffer.append("DeregisterYubiKeyOTPDeviceExtendedRequest(");
509
510    if (authenticationID != null)
511    {
512      buffer.append("authenticationID='");
513      buffer.append(authenticationID);
514      buffer.append("', ");
515    }
516
517    buffer.append("staticPasswordProvided=");
518    buffer.append(staticPassword != null);
519    buffer.append(", otpProvided=");
520    buffer.append(yubiKeyOTP != null);
521
522    final Control[] controls = getControls();
523    if (controls.length > 0)
524    {
525      buffer.append(", controls={");
526      for (int i=0; i < controls.length; i++)
527      {
528        if (i > 0)
529        {
530          buffer.append(", ");
531        }
532
533        buffer.append(controls[i]);
534      }
535      buffer.append('}');
536    }
537
538    buffer.append(')');
539  }
540}