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