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