001/*
002 * Copyright 2007-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2007-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) 2008-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.extensions;
037
038
039import com.unboundid.asn1.ASN1Element;
040import com.unboundid.asn1.ASN1OctetString;
041import com.unboundid.asn1.ASN1Sequence;
042import com.unboundid.ldap.sdk.Control;
043import com.unboundid.ldap.sdk.ExtendedResult;
044import com.unboundid.ldap.sdk.LDAPException;
045import com.unboundid.ldap.sdk.ResultCode;
046import com.unboundid.util.Debug;
047import com.unboundid.util.NotMutable;
048import com.unboundid.util.ThreadSafety;
049import com.unboundid.util.ThreadSafetyLevel;
050
051import static com.unboundid.ldap.sdk.extensions.ExtOpMessages.*;
052
053
054
055/**
056 * This class implements a data structure for storing the information from an
057 * extended result for the password modify extended request as defined in
058 * <A HREF="http://www.ietf.org/rfc/rfc3062.txt">RFC 3062</A>.  It is identical
059 * to the standard {@link ExtendedResult} object except that it is also able to
060 * extract the generated password if one was included.  See the documentation
061 * for the {@link PasswordModifyExtendedRequest} class for an example of this.
062 */
063@NotMutable()
064@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
065public final class PasswordModifyExtendedResult
066       extends ExtendedResult
067{
068  /**
069   * The serial version UID for this serializable class.
070   */
071  private static final long serialVersionUID = -160274020063799410L;
072
073
074
075  // The generated password from the response, if applicable.
076  private final ASN1OctetString generatedPassword;
077
078
079
080  /**
081   * Creates a new password modify extended result from the provided extended
082   * result.
083   *
084   * @param  extendedResult  The extended result to be decoded as a password
085   *                         modify extended result.  It must not be
086   *                         {@code null}.
087   *
088   * @throws  LDAPException  If the provided extended result cannot be decoded
089   *                         as a password modify extended result.
090   */
091  public PasswordModifyExtendedResult(final ExtendedResult extendedResult)
092         throws LDAPException
093  {
094    super(extendedResult);
095
096    final ASN1OctetString value = extendedResult.getValue();
097    if (value == null)
098    {
099      generatedPassword = null;
100      return;
101    }
102
103    final ASN1Element[] elements;
104    try
105    {
106      final ASN1Element valueElement = ASN1Element.decode(value.getValue());
107      elements = ASN1Sequence.decodeAsSequence(valueElement).elements();
108    }
109    catch (final Exception e)
110    {
111      Debug.debugException(e);
112      throw new LDAPException(ResultCode.DECODING_ERROR,
113                              ERR_PW_MODIFY_RESPONSE_VALUE_NOT_SEQUENCE.get(e),
114                              e);
115    }
116
117    if (elements.length == 0)
118    {
119      generatedPassword = null;
120      return;
121    }
122    else if (elements.length != 1)
123    {
124      throw new LDAPException(ResultCode.DECODING_ERROR,
125                              ERR_PW_MODIFY_RESPONSE_MULTIPLE_ELEMENTS.get());
126    }
127
128    generatedPassword = ASN1OctetString.decodeAsOctetString(elements[0]);
129  }
130
131
132
133  /**
134   * Creates a new password modify extended result with the provided
135   * information.
136   *
137   * @param  messageID          The message ID for the LDAP message that is
138   *                            associated with this LDAP result.
139   * @param  resultCode         The result code from the response.
140   * @param  diagnosticMessage  The diagnostic message from the response, if
141   *                            available.
142   * @param  matchedDN          The matched DN from the response, if available.
143   * @param  referralURLs       The set of referral URLs from the response, if
144   *                            available.
145   * @param  generatedPassword  The generated password for this response, if
146   *                            available.
147   * @param  responseControls   The set of controls from the response, if
148   *                            available.
149   */
150  public PasswordModifyExtendedResult(final int messageID,
151                                      final ResultCode resultCode,
152                                      final String diagnosticMessage,
153                                      final String matchedDN,
154                                      final String[] referralURLs,
155                                      final ASN1OctetString generatedPassword,
156                                      final Control[] responseControls)
157  {
158    super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs,
159          null, encodeValue(generatedPassword), responseControls);
160
161    this.generatedPassword = generatedPassword;
162  }
163
164
165
166  /**
167   * Encodes the value for this extended result using the provided information.
168   *
169   * @param  generatedPassword  The generated password for this response, if
170   *                            available.
171   *
172   * @return  An ASN.1 octet string containing the encoded value, or
173   *          {@code null} if there should not be an encoded value.
174   */
175  private static ASN1OctetString
176          encodeValue(final ASN1OctetString generatedPassword)
177  {
178    if (generatedPassword == null)
179    {
180      return null;
181    }
182
183    final ASN1Element[] elements =
184    {
185      new ASN1OctetString((byte) 0x80, generatedPassword.getValue())
186    };
187
188    return new ASN1OctetString(new ASN1Sequence(elements).encode());
189  }
190
191
192
193  /**
194   * Retrieves the string representation of the generated password contained in
195   * this extended result, if available.
196   *
197   * @return  The string representation of the generated password contained in
198   *          this extended result, or {@code null} if no generated password was
199   *          included in the extended result.
200   */
201  public String getGeneratedPassword()
202  {
203    if (generatedPassword == null)
204    {
205      return null;
206    }
207    else
208    {
209      return generatedPassword.stringValue();
210    }
211  }
212
213
214
215  /**
216   * Retrieves the binary representation of the generated password contained in
217   * this extended result, if available.
218   *
219   * @return  The binary representation of the generated password contained in
220   *          this extended result, or {@code null} if no generated password was
221   *          included in the extended result.
222   */
223  public byte[] getGeneratedPasswordBytes()
224  {
225    if (generatedPassword == null)
226    {
227      return null;
228    }
229    else
230    {
231      return generatedPassword.getValue();
232    }
233  }
234
235
236
237  /**
238   * Retrieves the raw generated password contained in this extended result, if
239   * available.
240   *
241   * @return  The raw generated password contained in this extended result, or
242   *          {@code null} if no generated password was included in the extended
243   *          result.
244   */
245  public ASN1OctetString getRawGeneratedPassword()
246  {
247    return generatedPassword;
248  }
249
250
251
252  /**
253   * {@inheritDoc}
254   */
255  @Override()
256  public String getExtendedResultName()
257  {
258    return INFO_EXTENDED_RESULT_NAME_PASSWORD_MODIFY.get();
259  }
260
261
262
263  /**
264   * Appends a string representation of this extended result to the provided
265   * buffer.
266   *
267   * @param  buffer  The buffer to which a string representation of this
268   *                 extended result will be appended.
269   */
270  @Override()
271  public void toString(final StringBuilder buffer)
272  {
273    buffer.append("PasswordModifyExtendedResult(resultCode=");
274    buffer.append(getResultCode());
275
276    final int messageID = getMessageID();
277    if (messageID >= 0)
278    {
279      buffer.append(", messageID=");
280      buffer.append(messageID);
281    }
282
283    if (generatedPassword != null)
284    {
285      buffer.append(", generatedPassword='");
286      buffer.append(generatedPassword.stringValue());
287      buffer.append('\'');
288    }
289
290    final String diagnosticMessage = getDiagnosticMessage();
291    if (diagnosticMessage != null)
292    {
293      buffer.append(", diagnosticMessage='");
294      buffer.append(diagnosticMessage);
295      buffer.append('\'');
296    }
297
298    final String matchedDN = getMatchedDN();
299    if (matchedDN != null)
300    {
301      buffer.append(", matchedDN='");
302      buffer.append(matchedDN);
303      buffer.append('\'');
304    }
305
306    final String[] referralURLs = getReferralURLs();
307    if (referralURLs.length > 0)
308    {
309      buffer.append(", referralURLs={");
310      for (int i=0; i < referralURLs.length; i++)
311      {
312        if (i > 0)
313        {
314          buffer.append(", ");
315        }
316
317        buffer.append('\'');
318        buffer.append(referralURLs[i]);
319        buffer.append('\'');
320      }
321      buffer.append('}');
322    }
323
324    final Control[] responseControls = getResponseControls();
325    if (responseControls.length > 0)
326    {
327      buffer.append(", responseControls={");
328      for (int i=0; i < responseControls.length; i++)
329      {
330        if (i > 0)
331        {
332          buffer.append(", ");
333        }
334
335        buffer.append(responseControls[i]);
336      }
337      buffer.append('}');
338    }
339
340    buffer.append(')');
341  }
342}