001/*
002 * Copyright 2008-2017 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2017 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.NotMutable;
035import com.unboundid.util.ThreadSafety;
036import com.unboundid.util.ThreadSafetyLevel;
037
038import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*;
039import static com.unboundid.util.Debug.*;
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 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 Alcatel-Lucent 8661
055 *   server products.  These classes provide support for proprietary
056 *   functionality or for external specifications that are not considered stable
057 *   or mature enough to be guaranteed to work in an interoperable way with
058 *   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 *             ... },
152 *      opValues     SEQUENCE OF OCTET STRING OPTIONAL }
153 * </PRE>
154 * <BR>
155 * <H2>Example</H2>
156 * The following example demonstrates the use of the password policy state
157 * extended operation to administratively disable a user's account:
158 * <PRE>
159 * PasswordPolicyStateOperation disableOp =
160 *      PasswordPolicyStateOperation.createSetAccountDisabledStateOperation(
161 *           true);
162 * PasswordPolicyStateExtendedRequest pwpStateRequest =
163 *      new PasswordPolicyStateExtendedRequest(
164 *               "uid=john.doe,ou=People,dc=example,dc=com", disableOp);
165 * PasswordPolicyStateExtendedResult pwpStateResult =
166 *      (PasswordPolicyStateExtendedResult)
167 *      connection.processExtendedOperation(pwpStateRequest);
168 *
169 * // NOTE:  The processExtendedOperation method will generally only throw an
170 * // exception if a problem occurs while trying to send the request or read
171 * // the response.  It will not throw an exception because of a non-success
172 * // response.
173 *
174 * if (pwpStateResult.getResultCode() == ResultCode.SUCCESS)
175 * {
176 *   boolean isDisabled = pwpStateResult.getBooleanValue(
177 *        PasswordPolicyStateOperation.OP_TYPE_GET_ACCOUNT_DISABLED_STATE);
178 *   if (isDisabled)
179 *   {
180 *     // The user account has been disabled.
181 *   }
182 *   else
183 *   {
184 *     // The user account is not disabled.
185 *   }
186 * }
187 * </PRE>
188 */
189@NotMutable()
190@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
191public final class PasswordPolicyStateExtendedRequest
192       extends ExtendedRequest
193{
194  /**
195   * The OID (1.3.6.1.4.1.30221.1.6.1) for the password policy state extended
196   * request.
197   */
198  public static final String PASSWORD_POLICY_STATE_REQUEST_OID =
199       "1.3.6.1.4.1.30221.1.6.1";
200
201
202
203  /**
204   * The serial version UID for this serializable class.
205   */
206  private static final long serialVersionUID = -1644137695182620213L;
207
208
209
210  // The set of password policy state operations to process.
211  private final PasswordPolicyStateOperation[] operations;
212
213  // The DN of the user account on which to operate.
214  private final String userDN;
215
216
217
218  /**
219   * Creates a new password policy state extended request with the provided user
220   * DN and optional set of operations.
221   *
222   * @param  userDN      The DN of the user account on which to operate.
223   * @param  operations  The set of password policy state operations to process.
224   *                     If no operations are provided, then the effect will be
225   *                     to retrieve the values of all available password policy
226   *                     state properties.
227   */
228  public PasswordPolicyStateExtendedRequest(final String userDN,
229              final PasswordPolicyStateOperation... operations)
230  {
231    this(userDN, null, operations);
232  }
233
234
235
236  /**
237   * Creates a new password policy state extended request with the provided user
238   * DN, optional set of operations, and optional set of controls.
239   *
240   * @param  userDN      The DN of the user account on which to operate.
241   * @param  controls    The set of controls to include in the request.
242   * @param  operations  The set of password policy state operations to process.
243   *                     If no operations are provided, then the effect will be
244   *                     to retrieve the values of all available password policy
245   *                     state properties.
246   */
247  public PasswordPolicyStateExtendedRequest(final String userDN,
248              final Control[] controls,
249              final PasswordPolicyStateOperation... operations)
250  {
251    super(PASSWORD_POLICY_STATE_REQUEST_OID, encodeValue(userDN, operations),
252          controls);
253
254    this.userDN     = userDN;
255    this.operations = operations;
256  }
257
258
259
260  /**
261   * Creates a new password policy state extended request from the provided
262   * generic extended request.
263   *
264   * @param  extendedRequest  The generic extended request to use to create this
265   *                          password policy state extended request.
266   *
267   * @throws  LDAPException  If a problem occurs while decoding the request.
268   */
269  public PasswordPolicyStateExtendedRequest(
270              final ExtendedRequest extendedRequest)
271         throws LDAPException
272  {
273    super(extendedRequest);
274
275    final ASN1OctetString value = extendedRequest.getValue();
276    if (value == null)
277    {
278      throw new LDAPException(ResultCode.DECODING_ERROR,
279                              ERR_PWP_STATE_REQUEST_NO_VALUE.get());
280    }
281
282    final ASN1Element[] elements;
283    try
284    {
285      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
286      elements = ASN1Sequence.decodeAsSequence(valueElement).elements();
287    }
288    catch (final Exception e)
289    {
290      debugException(e);
291      throw new LDAPException(ResultCode.DECODING_ERROR,
292                              ERR_PWP_STATE_REQUEST_VALUE_NOT_SEQUENCE.get(e),
293                              e);
294    }
295
296    if ((elements.length < 1) || (elements.length > 2))
297    {
298      throw new LDAPException(ResultCode.DECODING_ERROR,
299                              ERR_PWP_STATE_REQUEST_INVALID_ELEMENT_COUNT.get(
300                                   elements.length));
301    }
302
303    userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
304
305    if (elements.length == 1)
306    {
307      operations = new PasswordPolicyStateOperation[0];
308    }
309    else
310    {
311      try
312      {
313        final ASN1Element[] opElements =
314             ASN1Sequence.decodeAsSequence(elements[1]).elements();
315        operations = new PasswordPolicyStateOperation[opElements.length];
316        for (int i=0; i < opElements.length; i++)
317        {
318          operations[i] = PasswordPolicyStateOperation.decode(opElements[i]);
319        }
320      }
321      catch (final Exception e)
322      {
323        debugException(e);
324        throw new LDAPException(ResultCode.DECODING_ERROR,
325                                ERR_PWP_STATE_REQUEST_CANNOT_DECODE_OPS.get(e),
326                                e);
327      }
328    }
329  }
330
331
332
333  /**
334   * Encodes the provided information into an ASN.1 octet string that may be
335   * used as the value for this extended request.
336   *
337   * @param  userDN      The DN of the user account on which to operate.
338   * @param  operations  The set of operations to be processed.
339   *
340   * @return  An ASN.1 octet string containing the encoded value.
341   */
342  private static ASN1OctetString encodeValue(final String userDN,
343       final PasswordPolicyStateOperation[] operations)
344  {
345    final ASN1Element[] elements;
346    if ((operations == null) || (operations.length == 0))
347    {
348      elements = new ASN1Element[]
349      {
350        new ASN1OctetString(userDN)
351      };
352    }
353    else
354    {
355      final ASN1Element[] opElements = new ASN1Element[operations.length];
356      for (int i=0; i < operations.length; i++)
357      {
358        opElements[i] = operations[i].encode();
359      }
360
361      elements = new ASN1Element[]
362      {
363        new ASN1OctetString(userDN),
364        new ASN1Sequence(opElements)
365      };
366    }
367
368    return new ASN1OctetString(new ASN1Sequence(elements).encode());
369  }
370
371
372
373  /**
374   * Retrieves the DN of the user account on which to operate.
375   *
376   * @return  The DN of the user account on which to operate.
377   */
378  public String getUserDN()
379  {
380    return userDN;
381  }
382
383
384
385  /**
386   * Retrieves the set of password policy state operations to be processed.
387   *
388   * @return  The set of password policy state operations to be processed, or
389   *          an empty list if the values of all password policy state
390   *          properties should be retrieved.
391   */
392  public PasswordPolicyStateOperation[] getOperations()
393  {
394    return operations;
395  }
396
397
398
399  /**
400   * {@inheritDoc}
401   */
402  @Override()
403  public PasswordPolicyStateExtendedResult
404              process(final LDAPConnection connection, final int depth)
405         throws LDAPException
406  {
407    final ExtendedResult extendedResponse = super.process(connection, depth);
408    return new PasswordPolicyStateExtendedResult(extendedResponse);
409  }
410
411
412
413  /**
414   * {@inheritDoc}
415   */
416  @Override()
417  public PasswordPolicyStateExtendedRequest duplicate()
418  {
419    return duplicate(getControls());
420  }
421
422
423
424  /**
425   * {@inheritDoc}
426   */
427  @Override()
428  public PasswordPolicyStateExtendedRequest duplicate(final Control[] controls)
429  {
430    final PasswordPolicyStateExtendedRequest r =
431         new PasswordPolicyStateExtendedRequest(userDN, controls, operations);
432    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
433    return r;
434  }
435
436
437
438  /**
439   * {@inheritDoc}
440   */
441  @Override()
442  public String getExtendedRequestName()
443  {
444    return INFO_EXTENDED_REQUEST_NAME_PW_POLICY_STATE.get();
445  }
446
447
448
449  /**
450   * {@inheritDoc}
451   */
452  @Override()
453  public void toString(final StringBuilder buffer)
454  {
455    buffer.append("PasswordPolicyStateExtendedRequest(userDN='");
456    buffer.append(userDN);
457
458    if (operations.length > 0)
459    {
460      buffer.append("', operations={");
461      for (int i=0; i < operations.length; i++)
462      {
463        if (i > 0)
464        {
465          buffer.append(", ");
466        }
467
468        operations[i].toString(buffer);
469      }
470      buffer.append('}');
471    }
472
473    final Control[] controls = getControls();
474    if (controls.length > 0)
475    {
476      buffer.append(", controls={");
477      for (int i=0; i < controls.length; i++)
478      {
479        if (i > 0)
480        {
481          buffer.append(", ");
482        }
483
484        buffer.append(controls[i]);
485      }
486      buffer.append('}');
487    }
488
489    buffer.append(')');
490  }
491}