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 * <H2>Example</H2>
062 * The following example demonstrates the use of the password policy state
063 * extended operation to administratively disable a user's account:
064 * <PRE>
065 * PasswordPolicyStateOperation disableOp =
066 *      PasswordPolicyStateOperation.createSetAccountDisabledStateOperation(
067 *           true);
068 * PasswordPolicyStateExtendedRequest pwpStateRequest =
069 *      new PasswordPolicyStateExtendedRequest(
070 *               "uid=john.doe,ou=People,dc=example,dc=com", disableOp);
071 * PasswordPolicyStateExtendedResult pwpStateResult =
072 *      (PasswordPolicyStateExtendedResult)
073 *      connection.processExtendedOperation(pwpStateRequest);
074 *
075 * // NOTE:  The processExtendedOperation method will generally only throw an
076 * // exception if a problem occurs while trying to send the request or read
077 * // the response.  It will not throw an exception because of a non-success
078 * // response.
079 *
080 * if (pwpStateResult.getResultCode() == ResultCode.SUCCESS)
081 * {
082 *   boolean isDisabled = pwpStateResult.getBooleanValue(
083 *        PasswordPolicyStateOperation.OP_TYPE_GET_ACCOUNT_DISABLED_STATE);
084 *   if (isDisabled)
085 *   {
086 *     // The user account has been disabled.
087 *   }
088 *   else
089 *   {
090 *     // The user account is not disabled.
091 *   }
092 * }
093 * </PRE>
094 */
095@NotMutable()
096@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
097public final class PasswordPolicyStateExtendedRequest
098       extends ExtendedRequest
099{
100  /**
101   * The OID (1.3.6.1.4.1.30221.1.6.1) for the password policy state extended
102   * request.
103   */
104  public static final String PASSWORD_POLICY_STATE_REQUEST_OID =
105       "1.3.6.1.4.1.30221.1.6.1";
106
107
108
109  /**
110   * The serial version UID for this serializable class.
111   */
112  private static final long serialVersionUID = -1644137695182620213L;
113
114
115
116  // The set of password policy state operations to process.
117  private final PasswordPolicyStateOperation[] operations;
118
119  // The DN of the user account on which to operate.
120  private final String userDN;
121
122
123
124  /**
125   * Creates a new password policy state extended request with the provided user
126   * DN and optional set of operations.
127   *
128   * @param  userDN      The DN of the user account on which to operate.
129   * @param  operations  The set of password policy state operations to process.
130   *                     If no operations are provided, then the effect will be
131   *                     to retrieve the values of all available password policy
132   *                     state properties.
133   */
134  public PasswordPolicyStateExtendedRequest(final String userDN,
135              final PasswordPolicyStateOperation... operations)
136  {
137    this(userDN, null, operations);
138  }
139
140
141
142  /**
143   * Creates a new password policy state extended request with the provided user
144   * DN, optional set of operations, and optional set of controls.
145   *
146   * @param  userDN      The DN of the user account on which to operate.
147   * @param  controls    The set of controls to include in the request.
148   * @param  operations  The set of password policy state operations to process.
149   *                     If no operations are provided, then the effect will be
150   *                     to retrieve the values of all available password policy
151   *                     state properties.
152   */
153  public PasswordPolicyStateExtendedRequest(final String userDN,
154              final Control[] controls,
155              final PasswordPolicyStateOperation... operations)
156  {
157    super(PASSWORD_POLICY_STATE_REQUEST_OID, encodeValue(userDN, operations),
158          controls);
159
160    this.userDN     = userDN;
161    this.operations = operations;
162  }
163
164
165
166  /**
167   * Creates a new password policy state extended request from the provided
168   * generic extended request.
169   *
170   * @param  extendedRequest  The generic extended request to use to create this
171   *                          password policy state extended request.
172   *
173   * @throws  LDAPException  If a problem occurs while decoding the request.
174   */
175  public PasswordPolicyStateExtendedRequest(
176              final ExtendedRequest extendedRequest)
177         throws LDAPException
178  {
179    super(extendedRequest);
180
181    final ASN1OctetString value = extendedRequest.getValue();
182    if (value == null)
183    {
184      throw new LDAPException(ResultCode.DECODING_ERROR,
185                              ERR_PWP_STATE_REQUEST_NO_VALUE.get());
186    }
187
188    final ASN1Element[] elements;
189    try
190    {
191      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
192      elements = ASN1Sequence.decodeAsSequence(valueElement).elements();
193    }
194    catch (final Exception e)
195    {
196      debugException(e);
197      throw new LDAPException(ResultCode.DECODING_ERROR,
198                              ERR_PWP_STATE_REQUEST_VALUE_NOT_SEQUENCE.get(e),
199                              e);
200    }
201
202    if ((elements.length < 1) || (elements.length > 2))
203    {
204      throw new LDAPException(ResultCode.DECODING_ERROR,
205                              ERR_PWP_STATE_REQUEST_INVALID_ELEMENT_COUNT.get(
206                                   elements.length));
207    }
208
209    userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue();
210
211    if (elements.length == 1)
212    {
213      operations = new PasswordPolicyStateOperation[0];
214    }
215    else
216    {
217      try
218      {
219        final ASN1Element[] opElements =
220             ASN1Sequence.decodeAsSequence(elements[1]).elements();
221        operations = new PasswordPolicyStateOperation[opElements.length];
222        for (int i=0; i < opElements.length; i++)
223        {
224          operations[i] = PasswordPolicyStateOperation.decode(opElements[i]);
225        }
226      }
227      catch (final Exception e)
228      {
229        debugException(e);
230        throw new LDAPException(ResultCode.DECODING_ERROR,
231                                ERR_PWP_STATE_REQUEST_CANNOT_DECODE_OPS.get(e),
232                                e);
233      }
234    }
235  }
236
237
238
239  /**
240   * Encodes the provided information into an ASN.1 octet string that may be
241   * used as the value for this extended request.
242   *
243   * @param  userDN      The DN of the user account on which to operate.
244   * @param  operations  The set of operations to be processed.
245   *
246   * @return  An ASN.1 octet string containing the encoded value.
247   */
248  private static ASN1OctetString encodeValue(final String userDN,
249       final PasswordPolicyStateOperation[] operations)
250  {
251    final ASN1Element[] elements;
252    if ((operations == null) || (operations.length == 0))
253    {
254      elements = new ASN1Element[]
255      {
256        new ASN1OctetString(userDN)
257      };
258    }
259    else
260    {
261      final ASN1Element[] opElements = new ASN1Element[operations.length];
262      for (int i=0; i < operations.length; i++)
263      {
264        opElements[i] = operations[i].encode();
265      }
266
267      elements = new ASN1Element[]
268      {
269        new ASN1OctetString(userDN),
270        new ASN1Sequence(opElements)
271      };
272    }
273
274    return new ASN1OctetString(new ASN1Sequence(elements).encode());
275  }
276
277
278
279  /**
280   * Retrieves the DN of the user account on which to operate.
281   *
282   * @return  The DN of the user account on which to operate.
283   */
284  public String getUserDN()
285  {
286    return userDN;
287  }
288
289
290
291  /**
292   * Retrieves the set of password policy state operations to be processed.
293   *
294   * @return  The set of password policy state operations to be processed, or
295   *          an empty list if the values of all password policy state
296   *          properties should be retrieved.
297   */
298  public PasswordPolicyStateOperation[] getOperations()
299  {
300    return operations;
301  }
302
303
304
305  /**
306   * {@inheritDoc}
307   */
308  @Override()
309  public PasswordPolicyStateExtendedResult
310              process(final LDAPConnection connection, final int depth)
311         throws LDAPException
312  {
313    final ExtendedResult extendedResponse = super.process(connection, depth);
314    return new PasswordPolicyStateExtendedResult(extendedResponse);
315  }
316
317
318
319  /**
320   * {@inheritDoc}
321   */
322  @Override()
323  public PasswordPolicyStateExtendedRequest duplicate()
324  {
325    return duplicate(getControls());
326  }
327
328
329
330  /**
331   * {@inheritDoc}
332   */
333  @Override()
334  public PasswordPolicyStateExtendedRequest duplicate(final Control[] controls)
335  {
336    final PasswordPolicyStateExtendedRequest r =
337         new PasswordPolicyStateExtendedRequest(userDN, controls, operations);
338    r.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
339    return r;
340  }
341
342
343
344  /**
345   * {@inheritDoc}
346   */
347  @Override()
348  public String getExtendedRequestName()
349  {
350    return INFO_EXTENDED_REQUEST_NAME_PW_POLICY_STATE.get();
351  }
352
353
354
355  /**
356   * {@inheritDoc}
357   */
358  @Override()
359  public void toString(final StringBuilder buffer)
360  {
361    buffer.append("PasswordPolicyStateExtendedRequest(userDN='");
362    buffer.append(userDN);
363
364    if (operations.length > 0)
365    {
366      buffer.append("', operations={");
367      for (int i=0; i < operations.length; i++)
368      {
369        if (i > 0)
370        {
371          buffer.append(", ");
372        }
373
374        operations[i].toString(buffer);
375      }
376      buffer.append('}');
377    }
378
379    final Control[] controls = getControls();
380    if (controls.length > 0)
381    {
382      buffer.append(", controls={");
383      for (int i=0; i < controls.length; i++)
384      {
385        if (i > 0)
386        {
387          buffer.append(", ");
388        }
389
390        buffer.append(controls[i]);
391      }
392      buffer.append('}');
393    }
394
395    buffer.append(')');
396  }
397}