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