001/*
002 * Copyright 2008-2024 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-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) 2008-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 com.unboundid.asn1.ASN1Element;
041import com.unboundid.asn1.ASN1OctetString;
042import com.unboundid.asn1.ASN1Sequence;
043import com.unboundid.ldap.sdk.Control;
044import com.unboundid.ldap.sdk.ExtendedRequest;
045import com.unboundid.ldap.sdk.ExtendedResult;
046import com.unboundid.ldap.sdk.LDAPConnection;
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.ThreadSafety;
054import com.unboundid.util.ThreadSafetyLevel;
055
056import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
057
058
059
060/**
061 * This class provides an implementation of the password policy state extended
062 * request as used in the Ping Identity, UnboundID, or Nokia/Alcatel-Lucent 8661
063 * Directory Server.  It may be used to retrieve and/or alter password policy
064 * properties for a user account.  See the documentation in the
065 * {@link PasswordPolicyStateOperation} class for information about the types of
066 * operations that can be performed.
067 * <BR>
068 * <BLOCKQUOTE>
069 *   <B>NOTE:</B>  This class, and other classes within the
070 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
071 *   supported for use against Ping Identity, UnboundID, and
072 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
073 *   for proprietary functionality or for external specifications that are not
074 *   considered stable or mature enough to be guaranteed to work in an
075 *   interoperable way with other types of LDAP servers.
076 * </BLOCKQUOTE>
077 * <BR>
078 * The extended request has an OID of 1.3.6.1.4.1.30221.1.6.1 and a value with
079 * the following encoding:
080 * <PRE>
081 *   PasswordPolicyStateValue ::= SEQUENCE {
082 *        targetUser     LDAPDN
083 *        operations     SEQUENCE OF PasswordPolicyStateOperation OPTIONAL }
084 *
085 *   PasswordPolicyStateOperation ::= SEQUENCE {
086 *        opType       ENUMERATED {
087 *             getPasswordPolicyDN                          (0),
088 *             getAccountDisabledState                      (1),
089 *             setAccountDisabledState                      (2),
090 *             clearAccountDisabledState                    (3),
091 *             getAccountExpirationTime                     (4),
092 *             setAccountExpirationTime                     (5),
093 *             clearAccountExpirationTime                   (6),
094 *             getSecondsUntilAccountExpiration             (7),
095 *             getPasswordChangedTime                       (8),
096 *             setPasswordChangedTime                       (9),
097 *             clearPasswordChangedTime                     (10),
098 *             getPasswordExpirationWarnedTime              (11),
099 *             setPasswordExpirationWarnedTime              (12),
100 *             clearPasswordExpirationWarnedTime            (13),
101 *             getSecondsUntilPasswordExpiration            (14),
102 *             getSecondsUntilPasswordExpirationWarning     (15),
103 *             getAuthenticationFailureTimes                (16),
104 *             addAuthenticationFailureTime                 (17),
105 *             setAuthenticationFailureTimes                (18),
106 *             clearAuthenticationFailureTimes              (19),
107 *             getSecondsUntilAuthenticationFailureUnlock   (20),
108 *             getRemainingAuthenticationFailureCount       (21),
109 *             getLastLoginTime                             (22),
110 *             setLastLoginTime                             (23),
111 *             clearLastLoginTime                           (24),
112 *             getSecondsUntilIdleLockout                   (25),
113 *             getPasswordResetState                        (26),
114 *             setPasswordResetState                        (27),
115 *             clearPasswordResetState                      (28),
116 *             getSecondsUntilPasswordResetLockout          (29),
117 *             getGraceLoginUseTimes                        (30),
118 *             addGraceLoginUseTime                         (31),
119 *             setGraceLoginUseTimes                        (32),
120 *             clearGraceLoginUseTimes                      (33),
121 *             getRemainingGraceLoginCount                  (34),
122 *             getPasswordChangedByRequiredTime             (35),
123 *             setPasswordChangedByRequiredTime             (36),
124 *             clearPasswordChangedByRequiredTime           (37),
125 *             getSecondsUntilRequiredChangeTime            (38),
126 *             getPasswordHistory                           (39), -- Deprecated
127 *             clearPasswordHistory                         (40),
128 *             hasRetiredPassword                           (41),
129 *             getPasswordRetiredTime                       (42),
130 *             getRetiredPasswordExpirationTime             (43),
131 *             purgeRetiredPassword                         (44),
132 *             getAccountActivationTime                     (45),
133 *             setAccountActivationTime                     (46),
134 *             clearAccountActivationTime                   (47),
135 *             getSecondsUntilAccountActivation             (48),
136 *             getLastLoginIPAddress                        (49),
137 *             setLastLoginIPAddress                        (50),
138 *             clearLastLoginIPAddress                      (51),
139 *             getAccountUsabilityNotices                   (52),
140 *             getAccountUsabilityWarnings                  (53),
141 *             getAccountUsabilityErrors                    (54),
142 *             getAccountIsUsable                           (55),
143 *             getAccountIsNotYetActive                     (56),
144 *             getAccountIsExpired                          (57),
145 *             getPasswordExpirationTime                    (58),
146 *             getAccountIsFailureLocked                    (59),
147 *             setAccountIsFailureLocked                    (60),
148 *             getFailureLockoutTime                        (61),
149 *             getAccountIsIdleLocked                       (62),
150 *             getIdleLockoutTime                           (63),
151 *             getAccountIsResetLocked                      (64),
152 *             getResetLockoutTime                          (65),
153 *             getPasswordHistoryCount                      (66),
154 *             getPasswordIsExpired                         (67),
155 *             getAvailableSASLMechanisms                   (68),
156 *             getAvailableOTPDeliveryMechanisms            (69),
157 *             getHasTOTPSharedSecret                       (70),
158 *             getRegisteredYubiKeyPublicIDs                (71),
159 *             addRegisteredYubiKeyPublicID                 (72),
160 *             removeRegisteredYubiKeyPublicID              (73),
161 *             setRegisteredYubiKeyPublicIDs                (74),
162 *             clearRegisteredYubiKeyPublicIDs              (75),
163 *             addTOTPSharedSecret                          (76),
164 *             removeTOTPSharedSecret                       (77),
165 *             setTOTPSharedSecrets                         (78),
166 *             clearTOTPSharedSecrets                       (79),
167 *             hasRegisteredYubiKeyPublicID                 (80),
168 *             hasStaticPassword                            (81),
169 *             getLastBindPasswordValidationTime            (82),
170 *             getSecondsSinceLastBindPasswordValidation    (83),
171 *             setLastBindPasswordValidationTime            (84),
172 *             clearLastBindPasswordValidationTime          (85),
173 *             getAccountIsValidationLocked                 (86),
174 *             setAccountIsValidationLocked                 (87),
175 *             getRecentLoginHistory                        (88),
176 *             clearRecentLoginHistory                      (89),
177 *             ... },
178 *      opValues     SEQUENCE OF OCTET STRING OPTIONAL }
179 * </PRE>
180 * <BR>
181 * <H2>Example</H2>
182 * The following example demonstrates the use of the password policy state
183 * extended operation to administratively disable a user's account:
184 * <PRE>
185 * PasswordPolicyStateOperation disableOp =
186 *      PasswordPolicyStateOperation.createSetAccountDisabledStateOperation(
187 *           true);
188 * PasswordPolicyStateExtendedRequest pwpStateRequest =
189 *      new PasswordPolicyStateExtendedRequest(
190 *               "uid=john.doe,ou=People,dc=example,dc=com", disableOp);
191 * PasswordPolicyStateExtendedResult pwpStateResult =
192 *      (PasswordPolicyStateExtendedResult)
193 *      connection.processExtendedOperation(pwpStateRequest);
194 *
195 * // NOTE:  The processExtendedOperation method will generally only throw an
196 * // exception if a problem occurs while trying to send the request or read
197 * // the response.  It will not throw an exception because of a non-success
198 * // response.
199 *
200 * if (pwpStateResult.getResultCode() == ResultCode.SUCCESS)
201 * {
202 *   boolean isDisabled = pwpStateResult.getBooleanValue(
203 *        PasswordPolicyStateOperation.OP_TYPE_GET_ACCOUNT_DISABLED_STATE);
204 *   if (isDisabled)
205 *   {
206 *     // The user account has been disabled.
207 *   }
208 *   else
209 *   {
210 *     // The user account is not disabled.
211 *   }
212 * }
213 * </PRE>
214 */
215@NotMutable()
216@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
217public final class PasswordPolicyStateExtendedRequest
218       extends ExtendedRequest
219{
220  /**
221   * The OID (1.3.6.1.4.1.30221.1.6.1) for the password policy state extended
222   * request.
223   */
224  @NotNull public static final String PASSWORD_POLICY_STATE_REQUEST_OID =
225       "1.3.6.1.4.1.30221.1.6.1";
226
227
228
229  /**
230   * The serial version UID for this serializable class.
231   */
232  private static final long serialVersionUID = -1644137695182620213L;
233
234
235
236  // The set of password policy state operations to process.
237  @NotNull private final PasswordPolicyStateOperation[] operations;
238
239  // The DN of the user account on which to operate.
240  @NotNull private final String userDN;
241
242
243
244  /**
245   * Creates a new password policy state extended request with the provided user
246   * DN and optional set of operations.
247   *
248   * @param  userDN      The DN of the user account on which to operate.
249   * @param  operations  The set of password policy state operations to process.
250   *                     If no operations are provided, then the effect will be
251   *                     to retrieve the values of all available password policy
252   *                     state properties.
253   */
254  public PasswordPolicyStateExtendedRequest(@NotNull final String userDN,
255              @NotNull final PasswordPolicyStateOperation... operations)
256  {
257    this(userDN, null, operations);
258  }
259
260
261
262  /**
263   * Creates a new password policy state extended request with the provided user
264   * DN, optional set of operations, and optional set of controls.
265   *
266   * @param  userDN      The DN of the user account on which to operate.
267   * @param  controls    The set of controls to include in the request.
268   * @param  operations  The set of password policy state operations to process.
269   *                     If no operations are provided, then the effect will be
270   *                     to retrieve the values of all available password policy
271   *                     state properties.
272   */
273  public PasswordPolicyStateExtendedRequest(@NotNull final String userDN,
274              @Nullable final Control[] controls,
275              @NotNull final PasswordPolicyStateOperation... operations)
276  {
277    super(PASSWORD_POLICY_STATE_REQUEST_OID, encodeValue(userDN, operations),
278          controls);
279
280    this.userDN     = userDN;
281    this.operations = operations;
282  }
283
284
285
286  /**
287   * Creates a new password policy state extended request from the provided
288   * generic extended request.
289   *
290   * @param  extendedRequest  The generic extended request to use to create this
291   *                          password policy state extended request.
292   *
293   * @throws  LDAPException  If a problem occurs while decoding the request.
294   */
295  public PasswordPolicyStateExtendedRequest(
296              @NotNull final ExtendedRequest extendedRequest)
297         throws LDAPException
298  {
299    super(extendedRequest);
300
301    final ASN1OctetString value = extendedRequest.getValue();
302    if (value == null)
303    {
304      throw new LDAPException(ResultCode.DECODING_ERROR,
305                              ERR_PWP_STATE_REQUEST_NO_VALUE.get());
306    }
307
308    final ASN1Element[] elements;
309    try
310    {
311      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
312      elements = ASN1Sequence.decodeAsSequence(valueElement).elements();
313    }
314    catch (final Exception e)
315    {
316      Debug.debugException(e);
317      throw new LDAPException(ResultCode.DECODING_ERROR,
318                              ERR_PWP_STATE_REQUEST_VALUE_NOT_SEQUENCE.get(e),
319                              e);
320    }
321
322    if ((elements.length < 1) || (elements.length > 2))
323    {
324      throw new LDAPException(ResultCode.DECODING_ERROR,
325                              ERR_PWP_STATE_REQUEST_INVALID_ELEMENT_COUNT.get(
326                                   elements.length));
327    }
328
329    userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
330
331    if (elements.length == 1)
332    {
333      operations = new PasswordPolicyStateOperation[0];
334    }
335    else
336    {
337      try
338      {
339        final ASN1Element[] opElements =
340             ASN1Sequence.decodeAsSequence(elements[1]).elements();
341        operations = new PasswordPolicyStateOperation[opElements.length];
342        for (int i=0; i < opElements.length; i++)
343        {
344          operations[i] = PasswordPolicyStateOperation.decode(opElements[i]);
345        }
346      }
347      catch (final Exception e)
348      {
349        Debug.debugException(e);
350        throw new LDAPException(ResultCode.DECODING_ERROR,
351                                ERR_PWP_STATE_REQUEST_CANNOT_DECODE_OPS.get(e),
352                                e);
353      }
354    }
355  }
356
357
358
359  /**
360   * Encodes the provided information into an ASN.1 octet string that may be
361   * used as the value for this extended request.
362   *
363   * @param  userDN      The DN of the user account on which to operate.
364   * @param  operations  The set of operations to be processed.
365   *
366   * @return  An ASN.1 octet string containing the encoded value.
367   */
368  @NotNull()
369  private static ASN1OctetString encodeValue(@NotNull final String userDN,
370                      @Nullable final PasswordPolicyStateOperation[] operations)
371  {
372    final ASN1Element[] elements;
373    if ((operations == null) || (operations.length == 0))
374    {
375      elements = new ASN1Element[]
376      {
377        new ASN1OctetString(userDN)
378      };
379    }
380    else
381    {
382      final ASN1Element[] opElements = new ASN1Element[operations.length];
383      for (int i=0; i < operations.length; i++)
384      {
385        opElements[i] = operations[i].encode();
386      }
387
388      elements = new ASN1Element[]
389      {
390        new ASN1OctetString(userDN),
391        new ASN1Sequence(opElements)
392      };
393    }
394
395    return new ASN1OctetString(new ASN1Sequence(elements).encode());
396  }
397
398
399
400  /**
401   * Retrieves the DN of the user account on which to operate.
402   *
403   * @return  The DN of the user account on which to operate.
404   */
405  @NotNull()
406  public String getUserDN()
407  {
408    return userDN;
409  }
410
411
412
413  /**
414   * Retrieves the set of password policy state operations to be processed.
415   *
416   * @return  The set of password policy state operations to be processed, or
417   *          an empty list if the values of all password policy state
418   *          properties should be retrieved.
419   */
420  @NotNull()
421  public PasswordPolicyStateOperation[] getOperations()
422  {
423    return operations;
424  }
425
426
427
428  /**
429   * {@inheritDoc}
430   */
431  @Override()
432  @NotNull()
433  public PasswordPolicyStateExtendedResult process(
434              @NotNull final LDAPConnection connection, final int depth)
435         throws LDAPException
436  {
437    final ExtendedResult extendedResponse = super.process(connection, depth);
438    return new PasswordPolicyStateExtendedResult(extendedResponse);
439  }
440
441
442
443  /**
444   * {@inheritDoc}
445   */
446  @Override()
447  @NotNull()
448  public PasswordPolicyStateExtendedRequest duplicate()
449  {
450    return duplicate(getControls());
451  }
452
453
454
455  /**
456   * {@inheritDoc}
457   */
458  @Override()
459  @NotNull()
460  public PasswordPolicyStateExtendedRequest duplicate(
461              @Nullable final Control[] controls)
462  {
463    final PasswordPolicyStateExtendedRequest r =
464         new PasswordPolicyStateExtendedRequest(userDN, controls, operations);
465    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
466    r.setIntermediateResponseListener(getIntermediateResponseListener());
467    r.setReferralDepth(getReferralDepth());
468    r.setReferralConnector(getReferralConnectorInternal());
469    return r;
470  }
471
472
473
474  /**
475   * {@inheritDoc}
476   */
477  @Override()
478  @NotNull()
479  public String getExtendedRequestName()
480  {
481    return INFO_EXTENDED_REQUEST_NAME_PW_POLICY_STATE.get();
482  }
483
484
485
486  /**
487   * {@inheritDoc}
488   */
489  @Override()
490  public void toString(@NotNull final StringBuilder buffer)
491  {
492    buffer.append("PasswordPolicyStateExtendedRequest(userDN='");
493    buffer.append(userDN);
494
495    if (operations.length > 0)
496    {
497      buffer.append("', operations={");
498      for (int i=0; i < operations.length; i++)
499      {
500        if (i > 0)
501        {
502          buffer.append(", ");
503        }
504
505        operations[i].toString(buffer);
506      }
507      buffer.append('}');
508    }
509
510    final Control[] controls = getControls();
511    if (controls.length > 0)
512    {
513      buffer.append(", controls={");
514      for (int i=0; i < controls.length; i++)
515      {
516        if (i > 0)
517        {
518          buffer.append(", ");
519        }
520
521        buffer.append(controls[i]);
522      }
523      buffer.append('}');
524    }
525
526    buffer.append(')');
527  }
528}