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